|
|
|
Use of the PayPal payment system in ASP.NET |
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
1. IntroductionThose who create commercial sites are faced with the question: "How do I receive payments?" One of the most popular payment systems in the world is PayPal. This system is often chosen because it is reliable, easy to use, and allows an account to be opened easily. To open an account, you simply need to have a credit card and/or an account in an American bank. One of shortcomings of the system is its severe security policy. But, practice evidences that if you follow the rules of the system use carefully, errors are very infrequent. The purpose of this article is to show how payments processing can be organized |
to support reliability and security. The article is also aimed at providing you
with an example of development of a simplified version of an online shop to
demonstrate interaction with the PayPal system. You can use the code in your
applications to organize interaction with the PayPal system and to process
payments.
The article pays special attention to the process of automatic payment verification using IPN (Instant Payment Notification). The article is based on the experience of KB_Soft Group and the official PayPal documentation. |
|||||||||||||||||||||||||||||||||||||||||||||||||
2. Types of PayPal paymentsPayPal supports several types of payments: |
can organize a trial period to let the user assess the quality of services he
provides. The trial period can be either paid or free.
For the reasons described above, the article will consider the second option. The subscription will not be described to make the example simple. To interact with the PayPal system, KB_Soft Group uses a UserControl that is a product internally developed for these purposes. The given example of the code that works with PayPal uses a special HTML form for the request to make clear the explanation of interaction with the system. PayPal also provides its own control as a dynamic library, but, unfortunately, this control functions correctly only with American locales (en-us). Besides, it does not provide full functionality to work with PayPal. Neither does it provide the flexibility required to work on some projects. |
|||||||||||||||||||||||||||||||||||||||||||||||||
3. Payment processThe payment process is very simple. A POST form is created with a set of hidden fields that contain information about an item (identifier, name, and cost) and a button to send the form. It should be noted that all prices should be expressed with two digits after the point. If an item costs $10, its price should be expressed as "10.00". When the form is sent, the buyer goes to the paypal.com site and finishes the payment |
process. When a real PayPal account is used, the form should be sent to
https://www.paypal.com/cgi-bin/webscr. The developed example also
allows you to work with the PayPal Sandbox. Use the "UseSandbox" parameter of
web.config and the form will be sent to
https://www.sandbox.paypal.com/cgi-bin/webscr.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
3.1 "One-click" shoppingA code of the simplest form:
<form method="post" action= "https://www.paypal.com/cgi-bin/webscr">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="my@email.com">
<input type="hidden" name="item_name" value="Item name">
<input type="hidden" name="item_number" value="1234">
<input type="hidden" name="amount" value="19.95">
<input type="hidden" name="no_shipping" value="1">
<input type="submit" value="Buy Now">
</form>
Description of main parameters Table 1 – Main parameters of the request form.
Table 1 lists the most often used parameters. See the PayPal documentation for the full list of parameters (see the references at the end of the article). |
||||||||||||||||||||||||||||||||||||||||||||||||||
4. IPNIPN (Instant Payment Notification) is a PayPal technology allowing the automation of payments processing. The essence of the technology lies in a special script created on the seller's server. When an event happens related to the seller's account (for example payment transfer, payment cancel, subscription creation or cancel, and so on), the PayPal server sends a POST request with transaction information to the IPN script. The script in its turn sends a request to the PayPal server to verify the transaction.So, the buyer has performed a payment. After a delay (up to several seconds), the PayPal server sends the request to the IPN script that is specified in the account settings or passed in the notify_url parameter. A good IPN script is a key to payments security. If you have ever heard that the sellers who use PayPal are victims of somebody's cheating, be sure that those sellers either do not use IPN at all or have a poor IPN script. First of all, the script must make sure that it was called by the PayPal server. For these purposes, the script generates a POST request to https://www.paypal.com/cgi-bin/webscr (or to https://www.sandbox.paypal.com/cgi-bin/webscr) and passes all variables it received without any changes together with the cmd parameter having the _notify-validate value. As a response to the request, the script receives either VERIFIED (the transaction was successfully verified) or INVALID (in case of an error). If the script receives INVALID, it must terminate. Then, the script must check the payment recipient because a potential intruder may change the form for the payment to be sent to his account. The payment recipient is determined by the business and receiver_email variables. Two variables are necessary because PayPal allows several e-mails to be registered for one account. The e-mail that is specified during account creation is the primary one. The receiver_email is always the primary e-mail. If a payment was sent to another additional e-mail, the e-mail is passed in the business parameter. |
If business and/or receiver_email do not contain an expected
value, the script immediately terminates. Then, the script must
check the amount and the currency of the payment. This verification is required
because the potential intruder may change the payment amount in the form. In
case a subscription is used, the script should check all subscription
parameters (what parameters are set, duration and cost of trial periods,
duration and cost of the main subscription cycle, and the like).
An IPN for the same transaction can be sent more than once. For example, if a payment was delayed for some reason, the first IPN will be sent immediately after the payment. After the payment is performed or cancelled, the second IPN is sent. If the IPN script does not return the HTTP status equal to 200, PayPal sends the IPN again after some time. The first time it will be repeated in 10 seconds, then in 20 seconds if needed, then in 40, 80, and so forth (up to 24 hours). If script does not respond in four days, PayPal stops sending the IPN. This can be used to not lose transaction information if an error occurs in the IPN script. For example, if script fails to connect to the database where it stores transaction information, the script can return the HTTP status equal to 500 and the IPN will be repeated later. The repeated IPN will be sent the same way if the IPN script does not refer to the PayPal server to verify the transaction. As you can see from description of the return, rm, and notify_url parameters, the IPN can be passed to two scripts specified in the return and notify_url parameters. There are two differences between them: |
|||||||||||||||||||||||||||||||||||||||||||||||||
|
The received POST variables contain transaction information. The most widely used variables are the following: Table 2 – The most widely used variables.
|
||||||||||||||||||||||||||||||||||||||||||||||||||
5. An example of IPN processingGiven below is an example of a script that uses PayPal IPN. We publish this script not to provide you with a ready script that you can copy/paste, but to illustrate the general principles of working with IPN. KB_Soft Group uses much more complicated scripts to create sites using the PayPal system. This script is rather easy, but at the same time it illustrates the main principles of IPN processing.The given code creates a simplified version of an online shop. |
The buyer adds goods into the cart and pays for them. After the
buyer pays, a payment report is created.
All information about goods and cart contents is stored in XML files. We chose this way of information storage only for reasons of compatibility. Any user who has downloaded the code can easily adjust and test the created online shop. As for real applications, databases should be better used to store information about goods, carts, payment requests and responses to them. |
|||||||||||||||||||||||||||||||||||||||||||||||||
To store information about goods, we use the Goods.xml file
having the following structure:
<Goods>
<Good id="0" name="Sample of good" price="10.99" />
</Goods>
Where...
To store information about carts, we use the Carts.xml file having the following structure: <Carts>
<Cart rec_id="0" cart_id="1" item_id="0" price="10.99" quantity="1" />
</Carts>
Where...
To store information about payment requests, we use the PaymentRequests.xml file having the following structure: <Requests>
<Request request_id="0" cart_id="1" price="10.99"
request_date="5/28/2007 1:15:18 PM" />
</Requests>
Where...
To store information about responses to payment requests, we use the PaymentResponses.xml file having the following structure: <Responses>
<Response payment_id="0"
txn_id="3PP58082BD3079037"
payment_date="5/28/2007 1:22:40 PM"
payment_price="10.99"
email= my@email.com
first_name=""
last_name=""
street=""
city=""
state=""
zip=""
country=""
request_id="0"
is_success="True"
reason_fault=""
/>
</Responses>
Where...
The form of payment request that is sent to PayPal is as follows: <form id="payForm" method="post" action="<%Response.Write (URL)%>">
<input type="hidden" name="cmd" value="<%Response.Write (cmd)%>">
<input type="hidden" name="business"
value="<%Response.Write (business)%>">
<input type="hidden" name="item_name"
value="<%Response.Write (item_name)%>">
<input type="hidden" name="amount" value="<%Response.Write (amount)%>">
<input type="hidden" name="no_shipping"
value="<%Response.Write (no_shipping)%>">
<input type="hidden" name="return"
value="<%Response.Write (return_url)%>">
<input type="hidden" name="rm" value="<%Response.Write (rm)%>">
<input type="hidden" name="notify_url"
value="<%Response.Write (notify_url)%>">
<input type="hidden" name="cancel_return"
value="<%Response.Write (cancel_url)%>">
<input type="hidden" name="currency_code"
value="<%Response.Write (currency_code)%>">
<input type="hidden" name="custom"
value="<%Response.Write (request_id)%>">
</form>
Where...
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Values of the variables are set in the PayPal.aspx.cs (or
in PayPal.aspx.vb) file of the source code attached to the article.
See Table 1 for a more detailed description of the fields of the form.
When request_id is passed in the custom field,
it allows IPN script to restore information about the cart. If the buyer
cancels payment, he is redirected to cancel_url. However, if he
performs the payment, he is redirected to return_url. In the
latter case, we can test interaction with PayPal, check whether the payment was
performed, create a payment report and thank the buyer for the purchase. As for
the given example, use the code of IPN processing in the payment_success.aspx.cs
(or in payment_success.aspx.vb) file only for testing, since real
products should validate payments in the IPN script specified in the notify_url
parameter for the purposes of security. The payment_success.aspx.cs (or
payment_success.aspx.vb) code was specially written to make the
testing process give as much information as possible. The code contains
messages that are important only on the testing stage. This information is
written into a log file. The file stores not only critical errors, but also the
errors that allow site to keep on working.
In general, error messages should be properly handled, but not shown to users as exceptions. The Response.Write() construction is
not a good idea too. Real sites usually create a special page where information
about errors is sent. Then the information is formatted and shown to the user.
For example, the user should be redirected to this page if an exception is
thrown out or a page requested from the site is absent. To simplify the given
example, the code writes information about most errors that occur to the log
file.
The return parameter is useful because when |
the payment is performed, it allows the result of the verification to be shown
to the user. However, the verification does not provide a 100% guarantee that
the payment was really put into the seller's account. For example, if the buyer
uses an e-check, then the payment will be put into seller's account only after
the check is processed in a bank that also does not provide a guarantee that
the money is put into the account. That's why real online shops should use IPN
and work with payment, check the payment and protocol it in the code of the IPN
script. Besides, the content of the form should be encrypted before it is sent
in order to avoid forgery of the payment information. That means that so-called
Encrypted Website Payments should be used. If you are not going to use
Encrypted Website Payments (EWP) validation, you must check the price,
transaction ID, PayPal receiver email address and other data sent to you by IPN
to ensure that they are correct. By examining the data, you can be sure that
you are not being spoofed.
KB_Soft Group uses both EWP and validation of the parameters received from PayPal in its projects. This provides the duplicated validation check and rules out any possibility of information forgery. In order to simplify the given example of an online shop and to make it work on any PayPal account, we use only IPN. This is because if we use EWP we have to create private and public keys and upload the created public key to our account on the PayPal server. Then we would need to use the obtained identifier of certificate to encrypt the form of the request. Besides, to use EWP we need to download a public key of the PayPal system itself. This article is not aimed at describing in detail the principles of work with EWP, so you can visit the PayPal site to find detailed information on this issue instead. |
|||||||||||||||||||||||||||||||||||||||||||||||||
|
The IPNHandler class' Page_Load procedure code is given below. You
can find detailed information in the archives associated with the source code
attached to this article.
C#
private void Page_Load(object sender, EventArgs e)
{
string requestUriString;
CultureInfo provider = new CultureInfo("en-us");
string requestsFile = this.Server.MapPath(
"~/App_Data/PaymentRequests.xml");
requests.Clear();
if (System.IO.File.Exists(requestsFile))
{
requests.ReadXml(requestsFile);
}
else
{
Carts.CreateXml(requestsFile, "Requests");
requests.ReadXml(requestsFile);
}
string responseFile = this.Server.MapPath(
"~/App_Data/PaymentResponses.xml");
responses.Clear();
if (System.IO.File.Exists(responseFile))
{
responses.ReadXml(responseFile);
}
else
{
Carts.CreateXml(responseFile, "Responses");
responses.ReadXml(responseFile);
}
string strFormValues = Encoding.ASCII.GetString(
this.Request.BinaryRead(this.Request.ContentLength));
// getting the URL to work with
if (String.Compare(
ConfigurationManager.AppSettings["UseSandbox"].ToString(),
"true", false) == 0)
{
requestUriString =
"https://www.sandbox.paypal.com/cgi-bin/webscr";
}
else
{
requestUriString = "https://www.paypal.com/cgi-bin/webscr";
}
// Create the request back
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(requestUriString);
// Set values for the request back
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string obj2 = strFormValues + "&cmd=_notify-validate";
request.ContentLength = obj2.Length;
// Write the request back IPN strings
StreamWriter writer =
new StreamWriter(request.GetRequestStream(), Encoding.ASCII);
writer.Write(RuntimeHelpers.GetObjectValue(obj2));
writer.Close();
//send the request, read the response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
Encoding encoding = Encoding.GetEncoding("utf-8");
StreamReader reader = new StreamReader(responseStream, encoding);
// Reads 256 characters at a time.
char[] buffer = new char[0x101];
int length = reader.Read(buffer, 0, 0x100);
while (length > 0)
{
// Dumps the 256 characters to a string
string requestPrice;
string IPNResponse = new string(buffer, 0, length);
length = reader.Read(buffer, 0, 0x100);
try
{
// getting the total cost of the goods in
// cart for an identifier
// of the request stored in the "custom" variable
requestPrice =
GetRequestPrice(this.Request["custom"].ToString());
if (String.Compare(requestPrice, "", false) == 0)
{
Carts.WriteFile("Error in IPNHandler: amount = \");
reader.Close();
response.Close();
return;
}
}
catch (Exception exception)
{
Carts.WriteFile("Error in IPNHandler: " + exception.Message);
reader.Close();
response.Close();
return;
}
NumberFormatInfo info2 = new NumberFormatInfo();
info2.NumberDecimalSeparator = ".";
info2.NumberGroupSeparator = ",";
info2.NumberGroupSizes = new int[] { 3 };
// if the request is verified
if (String.Compare(IPNResponse, "VERIFIED", false) == 0)
{
// check the receiver's e-mail (login is user's
// identifier in PayPal)
// and the transaction type
if ((String.Compare(this.Request["receiver_email"],
this.business, false) != 0) ||
(String.Compare(this.Request["txn_type"],
"web_accept", false) != 0))
{
try
{
// parameters are not correct. Write a
// response from PayPal
// and create a record in the Log file.
this.CreatePaymentResponses(this.Request["txn_id"],
Convert.ToDecimal(
this.Request["mc_gross"], info2),
this.Request["payer_email"],
this.Request["first_name"],
this.Request["last_name"],
this.Request["address_street"],
this.Request["address_city"],
this.Request["address_state"],
this.Request["address_zip"],
this.Request["address_country"],
Convert.ToInt32(this.Request["custom"]), false,
"INVALID paymetn's parameters" +
"(receiver_email or txn_type)");
Carts.WriteFile(
"Error in IPNHandler: INVALID payment's" +
" parameters(receiver_email or txn_type)");
}
catch (Exception exception)
{
Carts.WriteFile("Error in IPNHandler: " +
exception.Message);
}
reader.Close();
response.Close();
return;
}
// check whether this request was performed
// earlier for its identifier
if (this.IsDuplicateID(this.Request["txn_id"]))
{
// the current request is processed. Write
// a response from PayPal
// and create a record in the Log file.
this.CreatePaymentResponses(this.Request["txn_id"],
Convert.ToDecimal(this.Request["mc_gross"], info2),
this.Request["payer_email"],
this.Request["first_name"],
this.Request["last_name"],
this.Request["address_street"],
this.Request["address_city"],
this.Request["address_state"],
this.Request["address_zip"],
this.Request["address_country"],
Convert.ToInt32(this.Request["custom"]), false,
"Duplicate txn_id found");
Carts.WriteFile(
"Error in IPNHandler: Duplicate txn_id found");
reader.Close();
response.Close();
return;
}
// the amount of payment, the status of the
// payment, amd a possible reason of delay
// The fact that Getting txn_type=web_accept or
// txn_type=subscr_payment are got odes not mean that
// seller will receive the payment.
// That's why we check payment_status=completed. The
// single exception is when the seller's account in
// not American and pending_reason=intl
if (((String.Compare(
this.Request["mc_gross"].ToString(provider),
requestPrice, false) != 0) ||
(String.Compare(this.Request["mc_currency"],
this.currency_code, false) != 0)) ||
((String.Compare(this.Request["payment_status"],
"Completed", false) != 0) &&
(String.Compare(this.Request["pending_reason"],
"intl", false) != 0)))
{
// parameters are incorrect or the payment
// was delayed. A response from PayPal should not be
// written to DB of an XML file
// because it may lead to a failure of
// uniqueness check of the request identifier.
// Create a record in the Log file with information
// about the request.
Carts.WriteFile(
"Error in IPNHandler: INVALID paymetn's parameters."+
"Request: " + strFormValues);
reader.Close();
response.Close();
return;
}
try
{
// write a response from PayPal
this.CreatePaymentResponses(this.Request["txn_id"],
Convert.ToDecimal(this.Request["mc_gross"], info2),
this.Request["payer_email"],
this.Request["first_name"],
this.Request["last_name"],
this.Request["address_street"],
this.Request["address_city"],
this.Request["address_state"],
this.Request["address_zip"],
this.Request["address_country"],
Convert.ToInt32(this.Request["custom"]), true, "");
Carts.WriteFile(
"Success in IPNHandler: PaymentResponses created");
///////////////////////////////////////////////////
// Here we notify the person responsible for
// goods delivery that
// the payment was performed and providing
// him with all needed information about
// the payment. Some flags informing that
// user paid for a services can be also set here.
// For example, if user paid for registration
// on the site, then the flag should be set
// allowing the user who paid to access the site
//////////////////////////////////////////////////
}
catch (Exception exception)
{
Carts.WriteFile(
"Error in IPNHandler: " + exception.Message);
}
}
else
{
Carts.WriteFile(
"Error in IPNHandler. IPNResponse = 'INVALID'");
}
}
reader.Close();
response.Close();
}
VisualBasic
Private Sub Page_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
Dim ci As CultureInfo = New CultureInfo("en-us")
Dim requestsFile As String = Server.MapPath(
"~/App_Data/PaymentRequests.xml")
requests.Clear()
If File.Exists(requestsFile) Then
requests.ReadXml(requestsFile)
Else
KBSoft.Carts.CreateXml(requestsFile, "Requests")
requests.ReadXml(requestsFile)
End If
Dim responseFile As String = Server.MapPath(
"~/App_Data/PaymentResponses.xml")
responses.Clear()
If File.Exists(responseFile) Then
responses.ReadXml(responseFile)
Else
KBSoft.Carts.CreateXml(responseFile, "Responses")
responses.ReadXml(responseFile)
End If
Dim strFormValues As String = Encoding.ASCII.GetString(
Request.BinaryRead(Request.ContentLength))
Dim strNewValue
' getting the URL to work with
Dim URL As String
If AppSettings("UseSandbox").ToString = "true" Then
URL = "https://www.sandbox.paypal.com/cgi-bin/webscr"
Else
URL = "https://www.paypal.com/cgi-bin/webscr"
End If
' Create the request back
Dim req As HttpWebRequest = CType(WebRequest.Create(URL),
HttpWebRequest)
' Set values for the request back
req.Method = "POST"
req.ContentType = "application/x-www-form-urlencoded"
strNewValue = strFormValues + "&cmd=_notify-validate"
req.ContentLength = strNewValue.Length
' Write the request back IPN strings
Dim stOut As StreamWriter = New StreamWriter(
req.GetRequestStream(), _
Encoding.ASCII)
stOut.Write(strNewValue)
stOut.Close()
'send the request, read the response
Dim strResponse As HttpWebResponse = CType(req.GetResponse(),
HttpWebResponse)
Dim IPNResponseStream As Stream = strResponse.GetResponseStream
Dim encode As Encoding = System.Text.Encoding.GetEncoding("utf-8")
Dim readStream As New StreamReader(IPNResponseStream, encode)
Dim read(256) As [Char]
' Reads 256 characters at a time.
Dim count As Integer = readStream.Read(read, 0, 256)
While count > 0
' Dumps the 256 characters to a string
Dim IPNResponse As New [String](read, 0, count)
count = readStream.Read(read, 0, 256)
Dim amount As String
Try
' getting the total cost of the goods in cart for an
' identifier of the request stored in the "custom"
' variable
amount = GetRequestPrice(Request("custom").ToString)
If amount = "" Then
KBSoft.Carts.WriteFile("Error in IPNHandler: amount = """)
readStream.Close()
strResponse.Close()
Return
End If
Catch ex As Exception
KBSoft.Carts.WriteFile("Error in IPNHandler: " + ex.Message)
readStream.Close()
strResponse.Close()
Return
End Try
Dim provider As NumberFormatInfo = New NumberFormatInfo()
provider.NumberDecimalSeparator = "."
provider.NumberGroupSeparator = ","
provider.NumberGroupSizes = New Integer() {3}
' if the request is verified
If IPNResponse = "VERIFIED" Then
' check the receiver's e-mail (login is user's
' identifier in PayPal) and the transaction type
If Request("receiver_email") <> business Or Request(
"txn_type") <> "web_accept" Then
Try
' parameters are not correct. Write a response from
' PayPal and create a record in the Log file.
CreatePaymentResponses(Request("txn_id"),
Convert.ToDecimal(Request("mc_gross"), provider), _
Request("payer_email"), Request("first_name"),
Request("last_name"), Request("address_street"), _
Request("address_city"), Request("address_state"),
Request("address_zip"), Request("address_country"), _
Convert.ToInt32(Request("custom")), False,
"INVALID paymetn's parameters (
receiver_email or txn_type)")
KBSoft.Carts.WriteFile(
"Error in IPNHandler: INVALID paymetn's parameters"+
" (receiver_email or txn_type)")
Catch ex As Exception
KBSoft.Carts.WriteFile(
"Error in IPNHandler: " + ex.Message)
End Try
readStream.Close()
strResponse.Close()
Return
End If
' check whether this request was performed earlier for its
' identifier
If IsDuplicateID(Request("txn_id")) Then
' the current request is processed. Write a response from
' PayPal and create a record in the Log file.
CreatePaymentResponses(Request("txn_id"),
Convert.ToDecimal(Request("mc_gross"), provider), _
Request("payer_email"), Request("first_name"),
Request("last_name"), Request("address_street"), _
Request("address_city"), Request("address_state"),
Request("address_zip"), Request("address_country"), _
Convert.ToInt32(Request("custom")), False,
"Duplicate txn_id found")
KBSoft.Carts.WriteFile(
"Error in IPNHandler: Duplicate txn_id found")
readStream.Close()
strResponse.Close()
Return
End If
' the amount of payment, the status of the payment, amd a
' possible reason of delay
' The fact that Getting txn_type=web_accept or
' txn_type=subscr_payment are got odes not mean that
' seller will receive the payment.
' That's why we check payment_status=completed. The
' single exception is when the seller's account in
' not American and pending_reason=intl
If Request("mc_gross").ToString(ci) <> amount Or Request(
"mc_currency") <> currency_code Or _
(Request("payment_status") <> "Completed" And Request(
"pending_reason") <> "intl") Then
' parameters are incorrect or the payment was delayed.
' A response from PayPal should not be
' written to DB of an XML file
' because it may lead to a failure of uniqueness check of
' the request identifier.
' Create a record in the Log file with information about
' the request.
KBSoft.Carts.WriteFile(
"Error in IPNHandler: INVALID paymetn's parameters."+
" Request: " + strFormValues)
readStream.Close()
strResponse.Close()
Return
End If
Try
' write a response from PayPal
CreatePaymentResponses(Request("txn_id"),
Convert.ToDecimal(Request("mc_gross"), provider), _
Request("payer_email"), Request("first_name"),
Request("last_name"), Request("address_street"), _
Request("address_city"), Request("address_state"),
Request("address_zip"), Request("address_country"), _
Convert.ToInt32(Request("custom")), True, "")
KBSoft.Carts.WriteFile(
"Success in IPNHandler: PaymentResponses created")
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Here we notify the person responsible for goods delivery
' that the payment was performed and providing him with
' all needed information about the payment. Some flags
' informing that user paid for a services can be also
' set here. For example, if user paid for registration
' on the site, then the flag should be set
' allowing the user who paid to access the site
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Catch ex As Exception
KBSoft.Carts.WriteFile(
"Error in IPNHandler: " + ex.Message)
End Try
Else
KBSoft.Carts.WriteFile(
"Error in IPNHandler. IPNResponse = 'INVALID'")
End If
End While
readStream.Close()
strResponse.Close()
End Sub
|
||||||||||||||||||||||||||||||||||||||||||||||||||
6. Parameters of web.config adjustmentTo use the source code attached to this article, you need the web.config parameters to be correctly specified. While adjusting the parameters in the web.config file, you should pay a special attention to the appSettings settings:<appSettings>
<!-- PayPay parameters-->
<add key="BusinessEmail" value="mymail@mail.com"/>
<add key="CancelPurchaseUrl" value="http://YOUR_IP/paypal/default.aspx"/>
<add key="ReturnUrl" value="http://YOUR_IP/paypal/payment_success.aspx"/>
<add key="NotifyUrl" value="http://YOUR_IP/paypal/IPNHandler.aspx"/>
<add key="CurrencyCode" value="USD"/>
<add key="UseSandbox" value="true"/>
<add key="SendToReturnURL" value="true"/>
</appSettings>
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Specify the e-mail of the payment recipient in the BusinessEmail
parameter. This can be the e-mail that was used while creating an account on
PayPal or an alternative e-mail specified in the account parameters as the
alternative e-mail. The e-mail that is used as the login to the PayPal account
is usually specified in this parameter. As for the CancelPurchaseUrl,
ReturnUrl and NotifyUrl parameters: in YOUR_IP you
need to specify your global IP address -- not your IP address in local network
-- or a domain of the registered site on which the seller's site is hosted.
While testing, you may simply specify "localhost" instead of YOUR_IP. It should
be noted that IPN will function only if you correctly specify the global IP
address or the name of a registered domain. If you specify "localhost," then
only the script specified in the ReturnUrl parameter will be able
to support interaction with PayPal. The script specified in the NotifyUrl
parameter will not. You should keep in
|
mind that IPN may be blocked, depending on the Firewall settings.
The above links are given for the "paypal" virtual directory. If you use another virtual directory or site, you need to specify its name instead of "paypal." To check whether your NotifyUrl is valid, enter its
address into "Notification URL:" filed at Profile->Instant Payment
Notification Preferences->Edit in your PayPal Business or Premier account.
Check the checkbox on this page and click the "Save" button. If the URL is
valid, a message about successful validation will be shown.
The CurrencyCode parameter is used to specify the code
of the currency that is used for payment. The UseSandbox parameter
is used to switch between PayPal SandBox and real PayPal accounts. The SendToReturnURL
parameter is used to turn on/off notifications sending to return_url.
SendToReturnURL is recommended to be set to true only for the
purposes of testing.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
7. Use of the source codeArchives with the source code of a simplified online shop are attached to this article. You can use this code in your software products to support interaction with PayPal when you need to perform payments.To use the code supplied with the article, you need to have .NET Framework 2.0 or higher installed on your system. You also need to have a real or SandBox PayPal account. No additional requirements should be needed to open |
a SandBox account. However, to create a real PayPal account you need to have a
credit card and/or an account in any American bank. Make sure that the standard
WebClient service is running on your system. If you have Visual Studio 2005,
you can run tests by opening the paypal.sln solution and executing the
code. IPN will not be available in this case. An alternative option is the
creation of a virtual directory on the IIS server.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
8. ConclusionIn conclusion, I would like to give you some advice:payer_id.
|
txn_type=web_accept does not mean that the seller will receive
payment. You should always check if payment_status=completed. The
single exception is a seller whose account is not American and pending_reason=intl.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
9. References |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Offshore software development which feels in-house © 2000 - 2008 KB_Soft Group |
|
info@kbsoft-group.com
|