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:
- A Storefront installation with a properly configured connection to Amazon Business.
- The domain name of your Storefront installation, e.g.
example.com. We will use the placeholderYOUR_DOMAINfor the rest of the howto. - A pair of OAuth 2.0 credentials, called
YOUR_CLIENT_IDandYOUR_CLIENT_SECRETfor 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. - The email address of a user that has an account on Amazon Business, e.g.
joe@example.com. We will use theYOUR_EMAIL_ADDRESSplaceholder below.
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
- JavaScript
- C#
- Java
- Go
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
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://YOUR_DOMAIN/oauth/authorize',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: {
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
email: 'YOUR_EMAIL_ADDRESS'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
var client = new RestClient("https://YOUR_DOMAIN/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&email=YOUR_EMAIL_ADDRESS", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
HttpResponse<String> response = Unirest.post("https://YOUR_DOMAIN/oauth/authorize")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&email=YOUR_EMAIL_ADDRESS")
.asString();
package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
// Configure your URL
url := "https://YOUR_DOMAIN"
// Ask for the client_credentials OAuth 2.0 flow
data := url.Values{
"grant_type": []string{"client_credentials"},
"client_id": []string{YOUR_CLIENT_ID},
"client_secret": []string{YOUR_CLIENT_SECRET},
"email": []string{YOUR_EMAIL_ADDRESS},
}
requestBody := strings.NewReader(data.Encode())
// Prepare HTTP request
req, err := http.NewRequest("POST", baseURL+"/oauth/authorize", requestBody)
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/x-www-form-urlencoded")
// Execute the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// The HTTP response body will return JSON according to the OAuth 2.0 specification.
body, err := io.ReadAll(req.Body)
if err != nil {
panic(err)
}
fmt.Println(resp)
fmt.Println(string(body))
}
Make sure to propertly encode the data in case you're having unusual symbols in e.g. the email address.
Parameters
| Parameter | Description |
|---|---|
grant_type | Set this to client_credentials to ask for the OAuth 2.0 Client Credentials flow. |
client_id | Your OAuth Client ID. |
client_secret | Your OAuth Client Secret. |
email | The 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.
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 Code | Description |
|---|---|
400 Bad Request | The server understood your request but is unable to complete it, e.g. because a required parameter is missing. |
401 Unauthorized | You sent invalid credentials. |
500 Internal Server Error | Something 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
- JavaScript
- C#
- Java
- Go
curl --request GET \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/search?query=iphone'
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://YOUR_DOMAIN/api/v1/amazon/search',
headers: {
'content-type': 'application/json',
'authorization: bearer YOUR_ACCESS_TOKEN'
},
params: {
query: 'iphone'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
var client = new RestClient("https://YOUR_DOMAIN/api/v1/amazon/search");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "bearer YOUR_ACCESS_TOKEN");
request.AddParameter("query", "iphone");
IRestResponse response = client.Execute(request);
HttpResponse<String> response = Unirest.post("https://YOUR_DOMAIN/api/v1/amazon/search")
.header("content-type", "application/json")
.header("authorization", "bearer YOUR_ACCESS_TOKEN")
.queryString("query", "iphone")
.asString();
package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
// Configure your URL
url := "https://YOUR_DOMAIN"
// Query parameters
v := url.Values{}
v.Set("query", "iphone")
// Prepare HTTP request
req, err := http.NewRequest("GET", baseURL+"/api/v1/amazon/search?"+v.Encode(), http.NoBody)
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("authorization", "bearer "+YOUR_ACCESS_TOKEN)
// Execute the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// The HTTP response body will return JSON accordingly
body, err := io.ReadAll(req.Body)
if err != nil {
panic(err)
}
fmt.Println(resp)
fmt.Println(string(body))
}
Parameters
| Parameter | Description |
|---|---|
query | Set this to the keyword(s) that the user has typed into the search box. |
page | A 1-based page index into the search results. |
pageSize | The number of results to return for the page. The minimum is 1, the maximum (and default) is 24. |
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).
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).
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.
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"
}
]
}
]
}
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 Code | Description |
|---|---|
400 Bad Request | The server understood your request but is unable to complete it, e.g. because a required parameter is missing. |
401 Unauthorized | You sent invalid or expired credentials. |
500 Internal Server Error | Something went wrong on our side. |
Example:
{
"error": {
"code": 401,
"message": "Invalid or expired request",
"details": [
"Please ensure that access token is valid."
]
}
}
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
- JavaScript
- C#
- Java
- Go
curl --request GET \
--header 'authorization: YOUR_ACCESS_TOKEN' \
--url 'https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID'
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID',
headers: {
'content-type': 'application/json',
'authorization: bearer YOUR_ACCESS_TOKEN'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
var client = new RestClient("https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "bearer YOUR_ACCESS_TOKEN");
IRestResponse response = client.Execute(request);
HttpResponse<String> response = Unirest.post("https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID")
.header("content-type", "application/json")
.header("authorization", "bearer YOUR_ACCESS_TOKEN")
.asString();
package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
// Configure your URL
url := "https://YOUR_DOMAIN"
// Prepare HTTP request
req, err := http.NewRequest("GET", baseURL+"/api/v1/amazon/products/YOUR_PRODUCT_ID", http.NoBody)
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("authorization", "bearer "+YOUR_ACCESS_TOKEN)
// Execute the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// The HTTP response body will return JSON accordingly
body, err := io.ReadAll(req.Body)
if err != nil {
panic(err)
}
fmt.Println(resp)
fmt.Println(string(body))
}
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 Code | Description |
|---|---|
400 Bad Request | The server understood your request but is unable to complete it, e.g. because a required parameter is missing. |
401 Unauthorized | You sent invalid or expired credentials. |
500 Internal Server Error | Something 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.
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
- JavaScript
- C#
- Java
- Go
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"}'
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID/punchout',
headers: {
'content-type': 'application/json',
'authorization: bearer YOUR_ACCESS_TOKEN'
},
json: {
callbackUrl: YOUR_HOOK_URL,
name: "Joe Average",
shipTo: {
street: "...",
city: "...",
state: "...",
postalCode: "...",
countryCode: "...",
country: "..."
}
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
var client = new RestClient("https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID/punchout");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "bearer YOUR_ACCESS_TOKEN");
request.AddStringBody(`{"callbackUrl": YOUR_HOOK_URL}`, ContentType.Json)
IRestResponse response = client.Execute(request);
HttpResponse<String> response = Unirest.post("https://YOUR_DOMAIN/api/v1/amazon/products/YOUR_PRODUCT_ID/punchout")
.header("content-type", "application/json")
.header("authorization", "bearer YOUR_ACCESS_TOKEN")
.body("{\"callbackUrl\": YOUR_HOOK_URL}")
.asString();
package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
// Configure your URL
url := "https://YOUR_DOMAIN"
// Setup the request body
var data = struct {
CallbackURL string `json:"callbackUrl,omitempty"`
}{
CallbackURL: YOUR_HOOK_URL,
}
body, err := json.Marshal(data)
if err != nil {
panic(err)
}
requestBody := bytes.NewReader(body)
// Prepare HTTP request
req, err := http.NewRequest("POST", baseURL+"/api/v1/amazon/products/YOUR_PRODUCT_ID/punchout", requestBody)
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("authorization", "bearer "+YOUR_ACCESS_TOKEN)
// Execute the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// The HTTP response body will return JSON accordingly
body, err := io.ReadAll(req.Body)
if err != nil {
panic(err)
}
fmt.Println(resp)
fmt.Println(string(body))
}
Parameters
| Parameter | Description |
|---|---|
callbackUrl | Set 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.
| Parameter | Description |
|---|---|
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 Code | Description |
|---|---|
400 Bad Request | The server understood your request but is unable to complete it, e.g. because a required parameter is missing. |
401 Unauthorized | You sent invalid or expired credentials. |
404 Not Found | The product, catalog, or vendor wasn't found. |
500 Internal Server Error | Something went wrong on our side. |