Blog

Blogging on programming and life in general.

Google Checkout Error - "Expected Serial Number was not contained in notification acknowledgment”

I’ve been busy lately integrating a payment provider into a site I am working in. After looking at the best payment providers, it came down to either using PayPal or Google Checkout. In the end I decided to use Google’s payment provider (as you can probably tell from my post title).

Before I start this post, I assume you have already created a sandbox Google Checkout account and know your way around setup and integration.

For my own Google Checkout integration, I needed to be able to add new transaction item in my database only if a customer has ordered an item and if their payment is approved. This is where Google’s call-back notification service comes into play.

I decided to use an synchronous notification process based on one the sample code that can be downloaded here: http://code.google.com/p/google-checkout-dotnet-sample-code/downloads/list.

Just using the sample code provided by Google out-the-box caused issues. It seems that the code samples do not correctly reflect version changes to the payment provider. One of the repeating errors I got was: “Expected serial number was not contained in notification acknowledgement”.

Google Checkout ErrorList

You will only receive this error only if you are using API version 2.5 and have “Notification Filtering” enabled in account settings. Unfortunately, notification filtering is something I needed to ensure both Google Checkout and my database transactions were in sync.

The Integration Issue error log showed me that the transaction serial number was not getting populated from my call-back notification page.

Google Checkout Error XML Detail

After a lot of debugging it became apparent that the notification page provided by Google Code sample was wrong! It was missing a key case statement: “authorization-amount-notification”. Once this was added no more errors occurred.

If you are using the “notification_extended.aspx”, “notification.aspx” or “notification_handshake.aspx” code samples. Be sure to make the following change:

<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="GCheckout" %>
<%@ Import Namespace="GCheckout.AutoGen" %>
<%@ Import Namespace="GCheckout.Util" %>
<script runat="server" language="c#">

  public string SerialNumber = "";

  void Page_Load(Object sender, EventArgs e) {
    // Extract the XML from the request.
    Stream RequestStream = Request.InputStream;
    StreamReader RequestStreamReader = new StreamReader(RequestStream);
    string RequestXml = RequestStreamReader.ReadToEnd();
    RequestStream.Close();
    // Act on the XML.
    switch (EncodeHelper.GetTopElement(RequestXml)) {
      case "new-order-notification":
        NewOrderNotification N1 = (NewOrderNotification) EncodeHelper.Deserialize(RequestXml, typeof(NewOrderNotification));
        SerialNumber = N1.serialnumber;
        string OrderNumber1 = N1.googleordernumber;
        string ShipToName = N1.buyershippingaddress.contactname;
        string ShipToAddress1 = N1.buyershippingaddress.address1;
        string ShipToAddress2 = N1.buyershippingaddress.address2;
        string ShipToCity = N1.buyershippingaddress.city;
        string ShipToState = N1.buyershippingaddress.region;
        string ShipToZip = N1.buyershippingaddress.postalcode;
        foreach (Item ThisItem in N1.shoppingcart.items) {
          string Name = ThisItem.itemname;
          int Quantity = ThisItem.quantity;
          decimal Price = ThisItem.unitprice.Value;
        }
        break;
      case "risk-information-notification":
        RiskInformationNotification N2 = (RiskInformationNotification) EncodeHelper.Deserialize(RequestXml, typeof(RiskInformationNotification));
        // This notification tells us that Google has authorized the order and it has passed the fraud check.
        // Use the data below to determine if you want to accept the order, then start processing it.
        SerialNumber = N2.serialnumber;
        string OrderNumber2 = N2.googleordernumber;
        string AVS = N2.riskinformation.avsresponse;
        string CVN = N2.riskinformation.cvnresponse;
        bool SellerProtection = N2.riskinformation.eligibleforprotection;
        break;
      case "order-state-change-notification":
        OrderStateChangeNotification N3 = (OrderStateChangeNotification) EncodeHelper.Deserialize(RequestXml, typeof(OrderStateChangeNotification));
        // The order has changed either financial or fulfillment state in Google's system.
        SerialNumber = N3.serialnumber;
        string OrderNumber3 = N3.googleordernumber;
        string NewFinanceState = N3.newfinancialorderstate.ToString();
        string NewFulfillmentState = N3.newfulfillmentorderstate.ToString();
        string PrevFinanceState = N3.previousfinancialorderstate.ToString();
        string PrevFulfillmentState = N3.previousfulfillmentorderstate.ToString();
        break;
      case "charge-amount-notification":
        ChargeAmountNotification N4 = (ChargeAmountNotification) EncodeHelper.Deserialize(RequestXml, typeof(ChargeAmountNotification));
        // Google has successfully charged the customer's credit card.
        SerialNumber = N4.serialnumber;
        string OrderNumber4 = N4.googleordernumber;
        decimal ChargedAmount = N4.latestchargeamount.Value;
        break;
      case "refund-amount-notification":
        RefundAmountNotification N5 = (RefundAmountNotification) EncodeHelper.Deserialize(RequestXml, typeof(RefundAmountNotification));
        // Google has successfully refunded the customer's credit card.
        SerialNumber = N5.serialnumber;
        string OrderNumber5 = N5.googleordernumber;
        decimal RefundedAmount = N5.latestrefundamount.Value;
        break;
      case "chargeback-amount-notification":
        ChargebackAmountNotification N6 = (ChargebackAmountNotification) EncodeHelper.Deserialize(RequestXml, typeof(ChargebackAmountNotification));
        // A customer initiated a chargeback with his credit card company to get her money back.
        SerialNumber = N6.serialnumber;
        string OrderNumber6 = N6.googleordernumber;
        decimal ChargebackAmount = N6.latestchargebackamount.Value;
        break;
    // Edit: Additional case statement for "authorization-amount-notification"
      case "authorization-amount-notification":
        AuthorizationAmountNotification N7 = (AuthorizationAmountNotification)EncodeHelper.Deserialize(RequestXml, typeof(AuthorizationAmountNotification));
        // Information about a successful reauthorization for an order
        SerialNumber = N7.serialnumber;
        string OrderNumber7 = N7.googleordernumber;
        break;
      default:
        break;
    }
  }
</script>
<notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="<%=SerialNumber %>" />

Once I have got to grips on using Google Checkout I will add another blog post containing my full call-back solution.

blog comments powered by Disqus
;