I'm trying to get IPN working for my site but until now without any success.
I've red all PayPals documentation and i've setted up all the requires configurations to get IPN working.
Here's what i have done so far:
1. Created a dev account;
2. Updated my Website Payment Preferences to Auto Return: On;
3. Turned on Instant payment notifications in my profile properties;
4. Created a test payment option event:
protected void btCheckout_Click(object sender, EventArgs e)
{
var queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
queryString["cmd"] = "_cart";
queryString["business"] = "xpto-facilitator#xpto.com";
queryString["upload"] = "1";
queryString["item_name_1"] = "My Cart Item 1";
queryString["quantity_1"] = "1";
queryString["amount_1"] = "100.00";
queryString["shopping_url"] = "http://xpto.com/Client/Checkout";
queryString["return"] = "http://xpto.com/Client/Checkout";
queryString["notify_url"] = "http://xpto.com/CheckoutResult.aspx";
Response.Redirect("https://www.sandbox.paypal.com/cgi-bin/webscr?" + queryString.ToString());
}
5. Created a IPN page:
protected void Page_Load(object sender, EventArgs e)
{
//Post back to either sandbox or live
string strSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strSandbox);
//Set values for the request back
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
byte[] param = Request.BinaryRead(HttpContext.Current.Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
strRequest += "&cmd=_notify-validate";
req.ContentLength = strRequest.Length;
//Send the request to PayPal and get the response
StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
streamOut.Write(strRequest);
streamOut.Close();
StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
string strResponse = streamIn.ReadToEnd();
streamIn.Close();
if (strResponse == "VERIFIED")
{
//log for debugging purposes
LogManager.Error("CheckoutResult VERIFIED:" + strResponse);
}
else if (strResponse == "INVALID")
{
//log for debugging purposes
LogManager.Error("CheckoutResult INVALID: " + strResponse);
}
else
{
//log for debugging purposes
LogManager.Error("CheckoutResult something else: " + strResponse);
}
}
I manage to proceed with the checkout and successfully paid the items;
My IPN page wasn't executed because i don't have anything logged;
Tested my handler with the Instant Payment Notification (IPN) simulator and i always get the following error:
We could not send an IPN due to an HTTP error: 401: Unauthorized
What am i doing wrong? Am i missing anything?
The notify_url you're specifying for IPN is set to an endpoint that requires a login.
queryString["notify_url"] = "http://xpto.com/CheckoutResult.aspx";
This URL must be set to an endpoint that can accept and process POST requests from the IPN service without any login being required (I can't seem to find any documentation that specifically mentions this requirement). This is the primary reason why the IPN received by your listener must then be verified (which you look to be doing correctly) because prior to verification there's no way to fully trust the received request was sent by PayPal.
Related
EDIT
This question was for a workaround. Getting a successful login by using HttpWebRequests. Not on how to use the api.
Question
I noticed in the API there was no way to get a usernames password.
This is what I have now as a test. I thought I could just get the "Wrong user/pass" response first and go from there. All I get is the pages source code.
Anyone have any pointers or advice?
I am definitively logging in. In Account Admin and Login History, it shows me logging in. But the server is not serving any useful response text for the login. And now, I locked myself out using wrong passwords to sort through the streamreader lol.
public string DoVerification(string email, string password)
{
var request = (HttpWebRequest)WebRequest.Create("https://app.smartsheet.com/b/home");
var postData = "loginEmail=" + email;
postData += "&loginPassword=" + password;
postData += "&action=login";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
}
private void btnLogin_Click(object sender, EventArgs e)
{
string response = DoVerification("test#test.com", "12345");
MessageBox.Show(response.ToString());
}
It's unclear what you are trying to achieve or why you expect it to work.
There is no way to retrieve a password through the API. That would be a bad idea.
You aren't actually using the API. API endpoints start with https://api.smartsheet.com/2.0 and are documented here: http://smartsheet-platform.github.io/api-docs/
After comparing both sources from the returned response.
I have these two js functions.
Failed attempt
function loggedFailures() {
logExternalGTMEvent({'event': 'app-login-failure','method': 'onsite','error': 'AUTH_NO_MATCHING_USER'}); return true
}
Successful attempt
function loggedFailures() {
return false
}
I just simply check for one or the other.
And for the record, putting the users password in the api is not a bad idea.... Smartsheets lets us delete any user through the API, so I don't see what it would matter.
I am implementing Yahoo OAuth 2.0 given in the guide -https://developer.yahoo.com/oauth2/guide/
I am successful in getting the Access Code given in step 4 but in step 5 which says 'Exchange refresh token for new access token' my code is failing with error - 'The remote server returned an error: (401) Unauthorized.'
My application is placed in http://www.example.com/TutorialCode/YahooOAuth2.0/yahoooauth2.aspx and it gets the Access Token.
Now i am requesting the new access token from the refresh token in another page - http://www.example.com/TutorialCode/YahooOAuth2.0/newaccesstoken.aspx
that is the refresh token i copy and paste from previous page to this page and click button to get new access token but it is failing. My code is -
HTML
<asp:TextBox placeholder="Refresh Token" ID="refreshTokenTextBox" runat="server"></asp:TextBox>
<asp:Button ID="newAccessTokenButton" runat="server" Text="Get New Access Token" OnClick="newAccessTokenButton_Click" />
<div id="newDataDiv" runat="server"></div>
C#
protected void newAccessTokenButton_Click(object sender, EventArgs e)
{
string consumerKey = "xxxx";
string consumerSecret = "myconsumerkey";
string returnUrl = "http://www.example.com/TutorialCode/YahooOAuth2.0/newaccesstoken.aspx";
//string encodedReturnUrl = System.Web.HttpUtility.UrlEncode(returnUrl);
/*Exchange authorization code for Access Token by sending Post Request*/
Uri address = new Uri("https://api.login.yahoo.com/oauth2/get_token");
// Create the web request
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
// Set type to POST
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] headerByte = System.Text.Encoding.UTF8.GetBytes(consumerKey + ":" + consumerSecret);
string headerString = System.Convert.ToBase64String(headerByte);
request.Headers["Authorization"] = "Basic " + headerString;
// Create the data we want to send
StringBuilder data = new StringBuilder();
data.Append("client_id=" + consumerKey);
data.Append("&client_secret=" + consumerSecret);
data.Append("&redirect_uri=" + returnUrl);
data.Append("&refresh_token =" + refreshTokenTextBox.Text.Trim());
data.Append("&grant_type=refresh_token");
// Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
string responseFromServer = "";
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
responseFromServer = reader.ReadToEnd();
//ShowNewReceivedData(responseFromServer);
newDataDiv.InnerHtml = responseFromServer;
}
}
catch (Exception ex)
{
Response.Write(ex.Message+"<br/>"+ex.ToString());
}
}
Can somebody help me in getting the root cause of the problem?
Thanks
You need to URL encode the parameter values in the request. They may contain characters like & or = that would break the form encoding.
Other than that you may want to swap the legacy POST approach for a more recent, easier approach, as described in the answer in HTTP request with post
You can check your parameters with a curl command:
curl -u "${consumerKey}:${consumerSecret}" -d "grant_type=refresh_token&redirect_uri=${returnUrl}&refresh_token=${refreshToken}" https://api.login.yahoo.com/oauth2/get_token
I am trying to Notify the Device by the Push Notification
I Received this Response From THE GCM Server
{"multicast_id":8594338261894783737,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1355822022916886%8ae6056ef9fd7ecd"}]}
But Still Not get the Notification
With Knowledge That --> "success":1
But I Think there is something Wrong Here --> "canonical_ids":0
This Is My Code ...
private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json")
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
//
// MESSAGE CONTENT
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//
// CREATE REQUEST
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
Request.Method = "POST";
Request.KeepAlive = false;
Request.ContentType = postDataContentType;
Request.Headers.Add(HttpRequestHeader.Authorization, string.Format("key={0}",apiKey));
Request.ContentLength = byteArray.Length;
Stream dataStream = Request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
try
{
WebResponse Response = Request.GetResponse();
HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
{
Label1.Text = "Unauthorized - need new token";
}
else if (!ResponseCode.Equals(HttpStatusCode.OK))
{
Label1.Text = "Response from web service isn't OK";
}
StreamReader Reader = new StreamReader(Response.GetResponseStream());
string responseLine = Reader.ReadToEnd();
Reader.Close();
return responseLine;
}
catch (Exception e)
{
return "error";
}
// return "error";
}
and i call this method using
string deviceId = "APA91bHomX3zb6Y87fb4GAjyj8zIaI-tt1n6ZFmgtmu16nmLW7ntwnOyv4BXMH7RzQWk3JrKdLjttJMxKzvpFd3Kmrid_RzsC3zR46GLJGiZKERXOSIR8fYReBEfz1f0G_FIm5bPttWUBDwz9jPuF2lS8RQh-0DKbw";
string message = "some test message";
string tickerText = "example test GCM";
string contentTitle = "content title GCM";
string postData =
"{ \"registration_ids\": [ \"" + deviceId + "\" ], " +
"\"data\": {\"tickerText\":\"" + tickerText + "\", " +
"\"contentTitle\":\"" + contentTitle + "\", " +
"\"message\": \"" + message + "\"}}";
Label1.Text = SendGCMNotification("AIzaSyBEvtrtbbfy2-p2zS8Zi8DweZiRy8M-nZc", postData);
Thanks In Advance
Take a look at the Response format in the GCM documentation: http://developer.android.com/google/gcm/gcm.html#response
success Number of messages that were processed without an error.
What I understand that to mean is that GCM was able to process that message, it does not mean that the message was successfully sent to the device. (E.g. The device might be offline and will receive it later, but the message was successfully processed).
"canonical_ids":0 Does not mean that there was an error, it means that there were no devices that needed their ID's updated. You can read more about canonical ID's here: http://developer.android.com/google/gcm/adv.html#canonical
On the server side, as long as the application is behaving well,
everything should work normally. However, if a bug in the application
triggers multiple registrations for the same device, it can be hard to
reconcile state and you might end up with duplicate messages.
GCM provides a facility called "canonical registration IDs" to easily
recover from these situations. A canonical registration ID is defined
to be the ID of the last registration requested by your application.
This is the ID that the server should use when sending messages to the
device.
If later on you try to send a message using a different registration
ID, GCM will process the request as usual, but it will include the
canonical registration ID in the registration_id field of the
response. Make sure to replace the registration ID stored in your
server with this canonical ID, as eventually the ID you're using will
stop working.
I would suggest adding some logging code to your client, to make sure that you are not receiving the message. Specifically in your GCMIntentService classes onMessage() method.
First, let me say that I have been at this for far too long, and the parts where I am stuck with, I believe should be the simplest of tasks to accomplish. Yet, I am unable to do them. I am really confused.
I am integrating PayPal into my website. I've developed many websites before, but this is my first time at doing payments.
I have the following code (unmodified - which I copied and pasted [don't panic! I did this for a reason]):
// ASP .NET C#
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Web;
public partial class csIPNexample : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Post back to either sandbox or live
string strSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
string strLive = "https://www.paypal.com/cgi-bin/webscr";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strSandbox);
//Set values for the request back
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
byte[] param = Request.BinaryRead(HttpContext.Current.Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
strRequest += "&cmd=_notify-validate";
req.ContentLength = strRequest.Length;
//for proxy
//WebProxy proxy = new WebProxy(new Uri("http://url:port#"));
//req.Proxy = proxy;
//Send the request to PayPal and get the response
StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
streamOut.Write(strRequest);
streamOut.Close();
StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
string strResponse = streamIn.ReadToEnd();
streamIn.Close();
if (strResponse == "VERIFIED")
{
//check the payment_status is Completed
//check that txn_id has not been previously processed
//check that receiver_email is your Primary PayPal email
//check that payment_amount/payment_currency are correct
//process payment
}
else if (strResponse == "INVALID")
{
//log for manual investigation
}
else
{
//log response/ipn data for manual investigation
}
}
}
Now, I know what this code means, and I know what it does. The only part I am having difficulty with, is this part:
if (strResponse == "VERIFIED")
{
//check the payment_status is Completed
//check that txn_id has not been previously processed
//check that receiver_email is your Primary PayPal email
//check that payment_amount/payment_currency are correct
//process payment
}
else if (strResponse == "INVALID")
{
//log for manual investigation
}
else
{
//log response/ipn data for manual investigation
}
Which, you're probably laughing about right now. That's ok:
//check the payment_status is Completed
I think that line should be done like this:
#{
if(Request.QueryString["payment_status"] == "Completed")
{
// Payment status is completed.
}
}
And, I think I should do pretty much the same thing (getting the Request["etc"] variables and comparing their values) for the rest of the commented lines, and also matching the data with data inside the DB which relates to the user.
Can somebody please help me out? I really have looked everywhere, and it seems like all of the code samples online that I could find, never show you the code for this part.
Your help will be really appreciated.
Thank you
Your line will be like this, its replay with a post! the content is the VERIFIED, but the values are on post, not on url.
if (strResponse == "VERIFIED")
{
// Now All informations are on
HttpContext.Current.Request.Form;
// for example you get the invoice like this
HttpContext.Current.Request.Form["invoice"]
// or the payment_status like
HttpContext.Current.Request.Form["payment_status"]
}
else
{
//log for manual investigation
}
Now after the Response is Verified and the Payment_status is Completed, you have extra options on txn_type, and you can check if the email are correct, if the amount are correct etc. So your code as you ask it will be like:
#{
if(HttpContext.Current.Request.Form["payment_status"] == "Completed")
{
// Payment status is completed.
}
}
You can check if payment_status == "Completed" that means the order is completed but you also need to check if the amount is correct, the email is correct, and the other reasons are correct (like pending, echeck, hold)
I have tried to integrate paypal sandbox with my project in asp.net.
Redirection to paypal sandbox working extremely fine ! You can check out your cart ! You can make payment ! But the problem is when paypal set redirection to my Success.aspx page !
I got the error as
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 192.168.0.101:808
I am using stream writer Object !
Wait Let me post my code !
this is page_load even of Success.aspx
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Used parts from https://www.paypaltech.com/PDTGen/
// Visit above URL to auto-generate PDT script
authToken = WebConfigurationManager.AppSettings["PDTToken"];
//read in txn token from querystring
txToken = Request.QueryString.Get("tx");
query = string.Format("cmd=_notify-synch&tx={0}&at={1}", txToken, authToken);
// Create the request back
string url = WebConfigurationManager.AppSettings["PayPalSubmitUrl"];
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
// Set values for the request back
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = query.Length;
// Write the request back IPN strings
StreamWriter stOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
stOut.Write(query);
stOut.Close();
// Do the request to PayPal and get the response
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
strResponse = stIn.ReadToEnd();
stIn.Close();
// sanity check
Label2.Text = strResponse;
// If response was SUCCESS, parse response string and output details
if (strResponse.StartsWith("SUCCESS"))
{
PDTHolder pdt = PDTHolder.Parse(strResponse);
Label1.Text = string.Format("Thank you {0} {1} [{2}] for your payment of {3} {4}!",
pdt.PayerFirstName, pdt.PayerLastName, pdt.PayerEmail, pdt.GrossTotal, pdt.Currency);
}
else
{
Label1.Text = "Oooops, something went wrong...";
}
}
}
This sentence creates error !!
StreamWriter stOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
These type of exception occurs
Exception Details: System.Net.Sockets.SocketException:
A connection attempt failed because the connected party did
not properly respond after a period of time,
or established connection failed because connected
host has failed to respond 192.168.0.101:808
First off, do not mix PDT and IPN - just use IPN. Go into PayPal admin and make sure that the return URL is NOT set there and that PDT is NOT enabled.
There is an IPN class available online just for this purpose - some more info (Caveat: my own blog post):
http://codersbarn.com/?tag=/paypal
http://paypalipnclass.codeplex.com/releases/view/31282