A recent project required integrating one of the nation’s largest retailers with Amazon MWS. If you are anything like us, your first step might have been to scour Google, Amazon, or Stack Overflow for a reliable integration guide. Surely, an eCommerce behemoth the size of Amazon would have a treasure trove of readily available documentation. Sadly, despite Amazon’s size and popularity, we had trouble finding a guide that put our questions to rest. In this blog series, we will walk through the recent Amazon MWS integration we performed, detailing the pitfalls we encountered and how we handled them.
For the uninitiated, below is the basic selling process for a third-party seller on Amazon:
The third-party seller (our client in this case) loads inventory and product information onto their Amazon storefront.
Customers purchase products from the seller on Amazon.
The seller polls Amazon for new orders that were created within a specified timeframe.
The seller processes orders and notifies Amazon as they ship, refund, and cancel orders.
For this blog series, we will focus exclusively on steps three and four. We’re going to assume you already have a process that loads products on Amazon for customers to purchase. This means we are going to walk through building a robust backend system that polls Amazon for orders and processes them. In this entry, we are discussing polling Amazon for orders. Part two will cover sending notifications back to Amazon.
Before we get started, there are a few great resources on Amazon MWS. Take a look at the main MWS documentation and the Selling on Amazon Guide to XML.
Amazon offers a Java library for each of their endpoints (as well as a PHP and C# library). The libraries offer several helpful features, such as:
Implementing a backoff mechanism. Because a request can fail for many reasons, such as throttling by Amazon, the library implements a backoff algorithm that will retry up to five times (this is configurable), with increasing intervals between each request.
Translating request objects into the appropriate query parameters for the RESTful API. Instead of multiple endpoints for each API, Amazon provides multiple Actions on the endpoint.
Providing an XML reader, which converts the Amazon Order to and from XML, without requiring an extra dependency such as JAXB.
Unfortunately, Amazon does not host a public Maven repository for any of their JARs, which means you will need to manually provide the JAR for your project. Although the libraries may use nearly duplicate code in some circumstances, the JARs do not share dependencies, which leads to odd class names like MarketplaceWebService and MarketplaceWebServiceOrders.
Amazon has a long list of APIs that do everything from retrieving orders to uploading product feeds, so we can’t say exactly which APIs you will need. To process and ship orders, we used the Orders and Feeds APIs. Specifically, these APIs allow you to poll Amazon for orders, process them in your Order Management System, then notify Amazon as you ship the orders.
Amazon’s documentation for the Orders API lists six available actions. We will cover four of these actions: ListOrders, ListOrdersByNextToken, ListOrderItems, and ListOrderItemsByNextToken.
Polling Amazon for Orders
Retrieving order information with the Orders API works like this:
You poll Amazon for orders, passing in some constraint parameters, such as the Created Date, to the ListOrders action. Amazon responds with a list of orders.
If the results are too big to fit on a single response (around 100 orders in our experience), Amazon sends a NextToken. You then pass this NextToken into the ListOrdersByNextToken action to retrieve more results, until you have them all.
Using the Amazon Order ID that you received in the ListOrders response, you poll for each order’s corresponding order items with the ListOrderItems action. This gives you all the details of the order, such as the quantity and items sold.
As before, if the results are too big, you receive a NextToken in your response and pass it to the ListOrderItemsByNextToken action to retrieve the remaining order items.
The Orders API contains the details about orders and their corresponding items. First, we call ListOrders (documented here). To limit the amount of orders returned from the ListOrders action, we will send either the Created Date or the Updated Date in the ListOrdersRequest.
The documentation does not mention that there may be a four-hour delay between when an order is created and when the OrderStatus is updated to “Unshipped.” If your application polls frequently for orders using the CreatedAfter field, orders will typically be in a pending status and need to be verified at a later time. We suggest filtering results with the LastUpdatedAfter date and an OrderStatus of “Unshipped” or “PartiallyShipped.” These constraints allow your application to safely poll the last X minutes for new, unshipped orders.
If there is one mistake to avoid, it is combining the usage of CreatedAfter with an OrderStatus of “Unshipped.” Because of the delay mentioned above, orders may be unknowingly missed (see the following scenario).
In this scenario, because Order A is not guaranteed to be marked as Unshipped before Order B, Order A will not be retrieved.
1:05 p.m.: Order A is placed.
1:10 p.m.: Order B is placed.
4:55 p.m.: Order B is marked as Unshipped.
5:00 p.m.: Orders are polled that were created after 1:00 p.m. and before 4:58 p.m. (by default, two minutes before the current time) with an OrderStatus of Unshipped. Order B is returned.
5:05 p.m.: Order A is marked as Unshipped.
6:00 p.m.: Orders are polled that were created after 1:10 p.m. and before 5:58 p.m. No orders are returned.
Paging With the Next Token
When polling the ListOrders action, the response contains a field called NextToken, which if not empty will be used to poll ListOrdersByNextToken for the remaining orders. However, if a NextTokenCorrupted error occurs, the entire chain of calls to ListOrders and ListOrdersByNextToken will need to be repeated to retrieve the remaining orders.
Now that we have orders, we call the ListOrderItems operation to get the items purchased with those orders. For this action, you pass an Amazon Order ID and MWS returns the details of the items, taxes, and quantities sold. Like the ListOrders call, ListOrderItems also returns a NextToken to be used with the ListOrderItemsByNextToken action when there are too many results to fit in a single response.
Amazon Order & Items
There are a few important fields on the Order and OrderItem that we have called out below. You can read the documentation for both for more detailed information.
ItemTax: To retrieve the Tax Jurisdiction breakdown, an integration with Amazon’s Order Report in the reporting API is needed.
SellerOrderID: You can provide this ID to Amazon via the OrderAcknowledgement feed.
NumberOfItemsShipped / NumberOfItemsUnshipped: Occasionally both of these fields will be zero. This indicates that the buyer canceled the order. No further action should be required.
ShippingAddress: The shipping address has three fields for the address lines. Contrary to what you might expect, sometimes the AddressLine1 field is empty, and you need to look to Line2 or Line3 for the customer’s shipping address. Additionally, the phone is an optional field, which will occasionally be empty.
Hopefully, you have a better understanding of how to use the Orders API to poll Amazon for orders. Stay tuned for our next blog post in this series, which will cover how to use the Amazon MWS Feeds API to send shipment confirmations and cancel orders.