Skip to main content

Storefront API for Amazon Business

If you want to integrate Storefront into your existing infrastructure you can do so by using the various APIs that Storefront provides. By doing so, you end up using Storefront without ever actually seeing it. You control it via API calls, like a remote control. We call that scenario "headless".

To securely connect to Storefront APIs, you must use the OAuth 2.0 protocol, the leading industry-standard protocol for authorization. The technical details are laid out in detail in RFC 6479. If you are simply a user of the Storefront API, you can use one of the various OAuth 2.0 client libraries available for your platform of choice.

In this tutorial, we are going to show you how to use the Storefront API for Amazon Business. We are going to authenticate, execute a search, and get the details of a product.

Prerequisites

To follow this tutorial, you will need:

  1. A Storefront installation with a properly configured connection to Amazon Business.
  2. The domain name of your Storefront installation, e.g. example.com. We will use the placeholder YOUR_DOMAIN for the rest of the howto.
  3. A pair of OAuth 2.0 credentials, called YOUR_CLIENT_ID and YOUR_CLIENT_SECRET for the rest of the document. They will be used to authenticate API requests. You've either created those credentials yourself on the Admin UI, or our support team has provisioned and sent them to you.
  4. The email address of a user that has an account on Amazon Business, e.g. joe@example.com. We will use the YOUR_EMAIL_ADDRESS placeholder below.
caution

Remember to never share your YOUR_CLIENT_SECRET with anyone! Keep it safe, don't put it into source code, or share it with customers. Treat it as if it were the PIN of your bank account.

Authenticating with the API

As central to the OAuth 2.0 protocol, we need to get ourselves a token, a so-called access token, that will be used for subsequent requests. Notice that access tokens are short-lived, i.e. you need to create a new access token once the old one expires. According to the OAuth 2.0 specification, you create an access token by using YOUR_CLIENT_ID and YOUR_CLIENT_SECRET. You create access tokens per individual user, i.e. you cannot use an access token created for user A in requests of user B.

There are various options for creating the token. In this howto, we are using the so-called "Client Credentials" flow outlined in the OAuth 2.0 protocol.

The following section creates an access token for the user with YOUR_EMAIL_ADDRESS.

curl --request POST \
--url 'https://YOUR_DOMAIN/oauth/authorize' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id=YOUR_CLIENT_ID \
--data client_secret=YOUR_CLIENT_SECRET
--data email=YOUR_EMAIL_ADDRESS
note

Make sure to propertly encode the data in case you're having unusual symbols in e.g. the email address.

Parameters

ParameterDescription
grant_typeSet this to client_credentials to ask for the OAuth 2.0 Client Credentials flow.
client_idYour OAuth Client ID.
client_secretYour OAuth Client Secret.
emailThe email address of the user you want to create the token for.

Response

If everything goes well, you will receive a successful HTTP response with status 200 OK with a payload containing the access_token, token_type, and expires_in values:

{
"access_token": "HH3wr4...Neuz2PI",
"token_type": "bearer",
"expires_in": 300
}

Notice that the expires_in specifies the number of seconds until this access token expires.

note

If your access token is expired, you'll get a HTTP response with status 401 Unauthorized. Get yourself a new token when this happens.

Errors

In case of an error, you can use the HTTP status code and the response body to find out what went wrong.

HTTP Status CodeDescription
400 Bad RequestThe server understood your request but is unable to complete it, e.g. because a required parameter is missing.
401 UnauthorizedYou sent invalid credentials.
500 Internal Server ErrorSomething went wrong on our side.

The HTTP response body if formatted according to the OAuth 2.0 Specification Section 5.2.

Example:

{
"error": "invalid_request",
"error_description": "Invalid request"
}

Search API for Amazon Business

Now that we have an access token (we use YOUR_ACCESS_TOKEN as a placeholder in the code below), we can perform a search.

Here's how you do a search on Amazon for "iphone":

curl --request GET \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/search?query=iphone'

Parameters

ParameterDescription
querySet this to the keyword(s) that the user has typed into the search box.
pageA 1-based page index into the search results.
pageSizeThe number of results to return for the page. The minimum is 1, the maximum (and default) is 24.
note

The Search API has dozens of additional parameters that you can pass as a query parameter. However, these are dynamic and depend on the actual search context. E.g. different query parameters will only be allowed if you search in the Music department, and will not be available in the Electronics department.

Response

If everything goes well you will receive a successful HTTP response with status 200 OK with a payload containing the search results.

{
"id": "amazon",
"name": "Amazon Business",
"count": {
"value": 306,
"relation": "eq"
},
"data": [
{
"id": "s_CgpCMDdaUEtONllSEAIaAlVTIgVlbi1VUyjChT0",
"provider": "amazon",
"sku": "B07ZPKN6YR",
"name": "Apple iPhone 11, 64GB, Black - Unlocked (Renewed)",
"vendor": "Chubbiestech",
"price": {
"amount": 364,
"currency": "USD",
"formatted": "$ 364.00"
},
"preview": {
"url": "https://m.media-amazon.com/images/I/31PpUfTCiFL._SY500_.jpg",
"width": 366,
"height": 500,
"altText": "Apple iPhone 11, 64GB, Black - Unlocked (Renewed)"
},
"delivery": "Delivery Friday, June 3",
"availability": "In Stock.",
"priceTaxLabel": "incl. taxes"
},
...
],
"facets": [
{
"id": "category",
"name": "Department",
"values": [
{
"id": "search-alias#mobile",
"name": "Cell Phones \u0026 Accessories"
},
{
"id": "search-alias#electronics",
"name": "Electronics"
},
{
"id": "search-alias#garden",
"name": "Home \u0026 Kitchen"
},
{
"id": "search-alias#sporting",
"name": "Sports \u0026 Outdoors"
},
{
"id": "search-alias#office-products",
"name": "Office Products"
},
{
"id": "search-alias#fashion",
"name": "Clothing, Shoes \u0026 Jewelry"
}
]
},
{
"id": "is_prime",
"name": "Delivery Option",
"values": [
{
"id": "1-",
"name": "FREE Shipping"
}
]
},
...
]
}

The above is an excerpt of a response to the Search API.

On the top-level, you will get an id that is always "amazon" if you search with the Storefront API for Amazon Business. The name is a localized label for the section that provided the search results, i.e. "Amazon Business".

The count structure will indicate the number of results returned from Amazon as well as if its an exact number ("relation": "eq") or rather a lower bound ("relation": "gte").

The data array will contain the search results of the current page. Notice that the Search API will only return certain details of a product. To get all details available for a product, use the Product Details API (see below).

note

As a consequence of returning only a subset of the product details, you may not be able to add a product to the shopping cart directly. However, this is intended and a common concept in marketplaces, and Amazon Business is not an exception: By design, marketplaces offer products from multiple merchants. So it is not clear on the result-level which merchant you want to purchase the product from—only on the product detail level, you will get all offers and have to decide which offer you want to accept.

In other words: Always guide the user to a product detail page.

Finally, you might get back a facets array that allows you to further drill down into the search results. Notice that setting facets as additional filters might actually lead to more results, not less.

Facets

The facets returned as part of the search results are critical for building your user interface. They are the means that allow your users to dig deeply into the products available on Amazon Business. You might get back dozens of facets, and facets are constantly evolving on Amazon Business. E.g. you might get a facet that is only available during the Christmas season.

But don't worry. Although the actual facets are unknown to you as an API consumer, building a search request from the response is actually straightforward.

Let's look at the facets returned in a search response:

...
"facets": [
{
"id": "category",
"name": "Department",
"values": [
{
"id": "search-alias#mobile",
"name": "Cell Phones \u0026 Accessories"
},
{
"id": "search-alias#electronics",
"name": "Electronics"
},
{
"id": "search-alias#garden",
"name": "Home \u0026 Kitchen"
},
{
"id": "search-alias#sporting",
"name": "Sports \u0026 Outdoors"
},
{
"id": "search-alias#office-products",
"name": "Office Products"
}
]
},
{
"id": "is_prime",
"name": "Delivery Option",
"values": [
{
"id": "1-",
"name": "FREE Shipping"
}
]
}
],
...

With the example above, you can create e.g. a sidebar in the UI that shows the actual "Departments" and "Delivery Options" that Amazon returns as part of the response. So the UI might look like this:

**Department**

( ) Cell Phones & Accessories
( ) Electronics
( ) Home & Kitchen
( ) Sports & Outdoors
( ) Office Products

**Delivery Option**

( ) FREE Shipping

Now, if the user clicks on e.g. "Electronics", you need to start a new search request and inject category=search-alias#electronics into the query string. So you use the id from the "Department" facet as the query name (category), and set the id from the selected facet value as the query value (search-alias#electronics).

note

Always ensure you properly encode the URL when using the Search API. E.g. you need to URL-encode the query string.

To add another filter, simply do the same for that facet, e.g. is_prime=1-.

To remove a filter, check if the filter is already selected and remove it from the query string instead of adding it.

caution

Do not assume a fixed set of facets, ids, names, or values: They might change at any time!

Here's an example of searching for iphone in the "Electronics" department:

curl --request GET \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/search?query=iphone&category=search-alias%23electronics'
{
"id": "amazon",
"name": "Amazon Business",
"count": {
"value": 2404,
"relation": "eq"
},
"data": [
...
],
"facets": [
{
"id": "category",
"name": "Category",
"parents": [
{
"id": "",
"name": "Electronics",
"selected": true
}
],
"values": [
{
"id": "search-alias#electronics,node#281407",
"name": "Accessories \u0026 Supplies"
},
{
"id": "search-alias#electronics,node#502394",
"name": "Camera \u0026 Photo"
},
{
"id": "search-alias#electronics,node#3248684011",
"name": "Car \u0026 Vehicle Electronics"
},
...
]
},
{
"id": "price",
"name": "Price",
"values": [
{
"id": "1253503011",
"name": "Under $25"
},
{
"id": "1253504011",
"name": "$25 to $50"
},
{
"id": "1253505011",
"name": "$50 to $100"
},
{
"id": "1253506011",
"name": "$100 to $200"
},
{
"id": "1253507011",
"name": "$200 \u0026 Above"
}
]
},
{
"id": "availability",
"name": "Availability",
"values": [
{
"id": "2661600011",
"name": "In Stock Only"
},
{
"id": "2661601011",
"name": "Include Out of Stock"
}
]
},
{
"id": "delivery_day",
"name": "Delivery Day",
"values": [
{
"id": "8308920011",
"name": "Get It Today"
},
{
"id": "8308921011",
"name": "Get It by Tomorrow"
}
]
},
{
"id": "review-rating",
"name": "Avg. Customer Review",
"values": [
{
"id": "1248879011",
"name": "4 Stars \u0026 Up"
},
{
"id": "1248880011",
"name": "3 Stars \u0026 Up"
},
{
"id": "1248881011",
"name": "2 Stars \u0026 Up"
},
{
"id": "1248882011",
"name": "1 Star \u0026 Up"
}
]
},
{
"id": "is_prime",
"name": "Delivery Option",
"values": [
{
"id": "1249137011",
"name": "Free Shipping by Amazon"
}
]
},
{
"id": "cpf_eligible",
"name": "Climate Pledge Friendly",
"values": [
{
"id": "21512497011",
"name": "Climate Pledge Friendly"
}
]
},
{
"id": "lbr_brands_browse-bin",
"name": "Brand",
"values": [
{
"id": "SAMSUNG",
"name": "SAMSUNG"
},
{
"id": "Apple",
"name": "Apple"
},
{
"id": "LG",
"name": "LG"
},
{
"id": "Motorola",
"name": "Motorola"
},
{
"id": "Google",
"name": "Google"
},
{
"id": "Nokia",
"name": "Nokia"
},
{
"id": "HUAWEI",
"name": "HUAWEI"
}
]
},
{
"id": "condition-type",
"name": "Condition",
"values": [
{
"id": "New",
"name": "New"
},
{
"id": "Used",
"name": "Used"
},
{
"id": "Certified Refurbished",
"name": "Renewed"
}
]
}
]
}
note

Notice that the "category" facet is special in that it may return its parents. This allows you to create a UI that represents a hierarchical tree of categories.

Errors

In case of an error, you can use the HTTP status code and the response body to find out what went wrong.

HTTP Status CodeDescription
400 Bad RequestThe server understood your request but is unable to complete it, e.g. because a required parameter is missing.
401 UnauthorizedYou sent invalid or expired credentials.
500 Internal Server ErrorSomething went wrong on our side.

Example:

{
"error": {
"code": 401,
"message": "Invalid or expired request",
"details": [
"Please ensure that access token is valid."
]
}
}
note

Notice that the error response is different from the token endpoint. The reason is that the token endpoint and its behaviour and response schemas are defined by OAuth 2.0 specification. The Storefront API endpoints however have a more versatile structure, including optional details and hints about the exact error.

Search results are returned as such a JSON structure.

Product Details API for Amazon Business

Once we have a search result, we can retrieve all details of a product by means of the Product Details API. Technically, it's similar to how we execute a search: It's just a different endpoint and different request and response schema.

Again, we will use an access token (i.e. YOUR_ACCESS_TOKEN). You will need to pick up the id passed as part of a previous search result (the s_CgpCMDdaUEtONllSEAIaAlVTIgVlbi1VUyjChT0 in the following example):

...
{
"id": "s_CgpCMDdaUEtONllSEAIaAlVTIgVlbi1VUyjChT0",
"provider": "amazon",
"sku": "B07ZPKN6YR",
"name": "Apple iPhone 11, 64GB, Black - Unlocked (Renewed)",
...
},
...

We'll use YOUR_RESULT_ID as a placeholder in the following code snippets:

curl --request GET \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID'

Parameters

None.

Response

If everything goes well, you will receive a successful HTTP response with status 200 OK with a payload containing the search results.

{
"id": "s_CgpCMDdaUEtONllSEAIaAlVTIgVlbi1VUyjChT0",
"provider": "amazon",
"name": "Apple iPhone 11, 64GB, Black - Unlocked (Renewed)",
"offersCount": 4,
"taxonomies": [
...
],
"images": [
...
],
"offers": [
{
"id": "kBVluNB7",
"productId": "s_CgpCMDdaUEtONllSEAIaAlVTIgVlbi1VUyjChT0",
"provider": "amazon",
"price": {
"amount": 364,
"currency": "USD",
"formatted": "$ 364.00"
},
...
},
...
],
...
}

If you want to dig into the details of the response structure, please look into the API reference and/or the Swagger/OpenAPI specification.

Errors

In case of an error, you can use the HTTP status code and the response body to find out what went wrong.

HTTP Status CodeDescription
400 Bad RequestThe server understood your request but is unable to complete it, e.g. because a required parameter is missing.
401 UnauthorizedYou sent invalid or expired credentials.
500 Internal Server ErrorSomething went wrong on our side.

Checkout API for Amazon Business

The final step of using the Storefront API for Amazon Business is to add the product to the shopping cart.

caution

Right now, you cannot add the product/offer to the shopping cart directly. You must do so by performing a punchout to Amazon. We have simplified this process to reduce your efforts to a minimum.

In the future, you might be able to directly add a product/offer to the shopping cart. However, this comes with additional complexities regarding your order process. So, for now, using OCI punchout is the simplest option you can choose.

Once again, we need to use an access token (YOUR_ACCESS_TOKEN) to authenticate your request. You will also need to pass the YOUR_PRODUCT_ID again to initiate the punchout process. Finally, we will need a YOUR_HOOK_URL that we will use to return the shopping cart to your system as it is returned by Amazon.

curl --request POST \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID/punchout'
--data '{"callbackUrl": "YOUR_HOOK_URL"}'

Parameters

ParameterDescription
callbackUrlSet this to the URL you want Storefront to postback the shopping cart in OCI format.
name(optional) Name of the shopper.
shipTo(optional) Address that Amazon should use for sending the order.

Shipment address

The parameters of the shipment address are the same as those in the cXML specification.

ParameterDescription
addressId(optional) ID of the address.
addressIdDomain(optional) ID of the address.
street(optional) ID of the address.
cityCode(optional) ID of the address.
city(optional) ID of the address.
stateCode(optional) ID of the address.
state(optional) ID of the address.
postalCode(optional) ID of the address.
countryCode(optional) ID of the address.
country(optional) ID of the address.

Example:

<ShipTo>
<!-- addressId and addressIdDomain -->
<Address addressID="1000467">
<!-- Name of the tenant -->
<Name xml:lang="en">Example Inc.</Name>
<PostalAddress>
<!-- name -->
<DeliverTo>Joe Average</DeliverTo>
<Street>123 Main Street</Street>
<City>Sunnyvale</City>
<!-- stateCode and state -->
<State isoStateCode="US-CA">CA</State>
<PostalCode>94089</PostalCode>
<!-- countryCode and country -->
<Country isoCountryCode="US">United States</Country>
</PostalAddress>
</Address>
</ShipTo>

Response

If everything goes well, you will receive a successful HTTP response with status 200 OK with a payload containing a URL that you can send to the user agent to follow.

{
"redirectUrl": "https://www.amazon.com/eprocurement/initiate-clean-punchout/123-4567890-1234567"
}

Following this URL will bring the end-user to the detail page of the product she was looking at on your frontend.

Errors

In case of an error, you can use the HTTP status code and the response body to find out what went wrong.

HTTP Status CodeDescription
400 Bad RequestThe server understood your request but is unable to complete it, e.g. because a required parameter is missing.
401 UnauthorizedYou sent invalid or expired credentials.
404 Not FoundThe product, catalog, or vendor wasn't found.
500 Internal Server ErrorSomething went wrong on our side.