Echilon
Echilon

Reputation: 10244

PayPal - ExpressCheckout and Recurring Payments

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

Upvotes: 0

Views: 5014

Answers (2)

Craig Howard
Craig Howard

Reputation: 1689

I had the same error, but it was due to not redirecting to paypal, and then using the token after paypal redirects back to my site.

Upvotes: 0

Echilon
Echilon

Reputation: 10244

This was actually the date in the end, but it took me forever to notice. In the call to CreateRecurringPaymentsProfile, encoder["PROFILESTARTDATE"] = profileDate; was wrong. I was using the yyyy-MM-DDTHH:mm:ss format when I needed yyyy-MM-ddTHH:mm:ss (lowercase d's).

Upvotes: 2

Related Questions