I'm trying to get PayPal's ExpressCheckout working with Recurring Payments. I've got the first two stages (the calls to SetExpressCheckout and GetExpressCheckoutDetails) but CreateRecurringPaymentsProfile fails with the error below. I'm using a modified version of Paypal's sample code, but I suspect I'm (not) setting an encoder value. Anyone used this before?
The error:
// TIMESTAMP: 2010-10-27T09:57:47Z
// CORRELATIONID: ad2b2da33c672
// ACK: Failure
// VERSION: 51.0
// BUILD: 1553277
// L_ERRORCODE0: 11502
// L_SHORTMESSAGE0: Invalid Token
// L_LONGMESSAGE0: The token is invalid
// L_SEVERITYCODE0: Error
The code I'm using is:
/// This returns true
public bool SetExpressCheckout(string amt, ref string token, ref string retMsg)
{
string host = "www.paypal.com";
if (bSandbox) {
pendpointurl = "https://api-3t.sandbox.paypal.com/nvp";
host = "www.sandbox.paypal.com";
}
string baseUrl = "http://" + HttpContext.Current.Request.Url.Authority;
string[] returnUrlParts = WebConfigurationManager.AppSettings["PaypalReturnUrl"].Split('?'),
cancelUrlParts = WebConfigurationManager.AppSettings["PaypalCancelUrl"].Split('?');
string returnURL = baseUrl + VirtualPathUtility.ToAbsolute(returnUrlParts[0]) + (returnUrlParts.Length > 1 ? '?' + returnUrlParts.Skip(1).Aggregate((itms, itm) => itms + itm) : string.Empty),
cancelURL = baseUrl + VirtualPathUtility.ToAbsolute(cancelUrlParts[0]) + (cancelUrlParts.Length > 1 ? '?' + cancelUrlParts.Skip(1).Aggregate((itms, itm) => itms + itm) : string.Empty);
NVPCodec encoder = new NVPCodec();
encoder["METHOD"] = "SetExpressCheckout";
encoder["RETURNURL"] = returnURL;
encoder["CANCELURL"] = cancelURL;
encoder["AMT"] = amt;
//encoder["PAYMENTACTION"] = "SALE";
encoder["CURRENCYCODE"] = "GBP";
encoder["NOSHIPPING"] = "1";
encoder["L_BILLINGTYPE0"] = "RecurringPayments";
encoder["L_BILLINGAGREEMENTDESCRIPTION0"] = "Subscription for MySite";
string pStrrequestforNvp = encoder.Encode();
string pStresponsenvp = HttpCall(pStrrequestforNvp);
NVPCodec decoder = new NVPCodec();
decoder.Decode(pStresponsenvp);
string strAck = decoder["ACK"].ToLower();
if (strAck != null && (strAck == "success" || strAck == "successwithwarning")) {
token = decoder["TOKEN"];
string ECURL = "https://" + host + "/cgi-bin/webscr?cmd=_express-checkout" + "&token=" + token;
retMsg = ECURL;
return true;
} else {
retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
"Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
"Desc2=" + decoder["L_LONGMESSAGE0"];
return false;
}
}
/// This returns true
public bool GetExpressCheckoutDetails(string token, ref string PayerId, ref string retMsg)
{
if (bSandbox) {
pendpointurl = "https://api-3t.sandbox.paypal.com/nvp";
}
NVPCodec encoder = new NVPCodec();
encoder["METHOD"] = "GetExpressCheckoutDetails";
encoder["TOKEN"] = token;
string pStrrequestforNvp = encoder.Encode();
string pStresponsenvp = HttpCall(pStrrequestforNvp);
NVPCodec decoder = new NVPCodec();
decoder.Decode(pStresponsenvp);
string strAck = decoder["ACK"].ToLower();
if (strAck != null && (strAck == "success" || strAck == "successwithwarning")) {
return true;
} else {
retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
"Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
"Desc2=" + decoder["L_LONGMESSAGE0"];
return false;
}
}
// This fails and returns false with the following in the decoder result
// TIMESTAMP: 2010-10-27T09:57:47Z
// CORRELATIONID: ad2b2da33c672
// ACK: Failure
// VERSION: 51.0
// BUILD: 1553277
// L_ERRORCODE0: 11502
// L_SHORTMESSAGE0: Invalid Token
// L_LONGMESSAGE0: The token is invalid
// L_SEVERITYCODE0: Error
public bool CreateRecurringPaymentsProfileCode(string token, string amount, string profileDate, string billingPeriod, string billingFrequency, ref string retMsg)
{
NVPCallerServices caller = new NVPCallerServices();
IAPIProfile profile = ProfileFactory.createSignatureAPIProfile();
profile.APIUsername = this.APIUsername;
profile.APIPassword = this.APIPassword;
profile.APISignature = this.APISignature;
profile.Environment = "sandbox";
caller.APIProfile = profile;
string host = "www.paypal.com";
if (bSandbox) {
pendpointurl = "https://api-3t.sandbox.paypal.com/nvp";
host = "www.sandbox.paypal.com";
}
NVPCodec encoder = new NVPCodec();
encoder["VERSION"] = "51.0";
// Add request-specific fields to the request.
encoder["METHOD"] = "CreateRecurringPaymentsProfile";
encoder["TOKEN"] = token;
encoder["AMT"] = amount;
encoder["PROFILESTARTDATE"] = profileDate; //Date format from server expects Ex: 2006-9-6T0:0:0
encoder["BILLINGPERIOD"] = billingPeriod;
encoder["BILLINGFREQUENCY"] = billingFrequency;
encoder["L_BILLINGTYPE0"] = "RecurringPayments";
encoder["DESC"] = "Subscription for MySite";
// Execute the API operation and obtain the response.
string pStrrequestforNvp = encoder.Encode();
string pStresponsenvp = caller.Call(pStrrequestforNvp);
NVPCodec decoder = new NVPCodec();
decoder.Decode(pStresponsenvp);
//return decoder["ACK"];
string strAck = decoder["ACK"];
bool success = false;
if (strAck != null && (strAck == "Success" || strAck == "SuccessWithWarning")) {
success = true; // check decoder["result"]
} else {
success = false;
}
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < decoder.Keys.Count; i++) {
buffer.AppendFormat("{0}: {1}", decoder.Keys[i], decoder.GetValues(i).Aggregate((vals, val) => vals + "----" + val));
}
retMsg = buffer.ToString();
return success;// returns false
}
If it helps, the code which is calling it is :
NVPAPICaller ppapi = new NVPAPICaller();
NVPCodec decoder = new NVPCodec();
string retMsg = string.Empty,
token = Convert.ToString(Session["token"]),
finalPaymentAmount = "15",
payerId = Convert.ToString(Session["payerId"] ?? string.Empty); // set from SetExpressCheckout
bool shippingSuccess = ppapi.GetExpressCheckoutDetails(token, ref payerId, ref retMsg);
if (shippingSuccess) {
payerId = Session["payerId"].ToString();
btnConfirm.Enabled = false;
bool paymentSuccess = ppapi.CreateRecurringPaymentsProfileCode(token, finalPaymentAmount, DateTime.Now.ToString("yyyy-M-DTH:m:s"), "Year", "1", ref retMsg);
// but paymentSuccess is false