Feeds API v2020-09-04 Use Case Guide

AmazonSPAPI

# What is the Feeds API?

With the Selling Partner API for Feeds (Feeds API), you can build applications that enable sellers to upload information to Amazon that helps them manage their selling businesses. There are feeds for a wide variety of use cases, such as creating listings, managing inventory and prices, acknowledging orders, and more. See feedType values (opens new window) for a list of available feed types.

# Workflow for submitting a feed

Here are the high-level steps for submitting a feed:

  1. Call the createFeedDocument (opens new window) operation, specifying the content type for the feed that you are submitting.

    Amazon returns a feedDocumentId value, encryption details, and a URL for uploading the feed contents.

  2. Encrypt and upload your feed document contents to the URL from the previous step.

  3. Call the createFeed (opens new window) operation. Use the inputFeedDocumentId parameter to pass in the feedDocumentId value from step 1. Specify the marketplaces that you want the feed to be applied to and any relevant feed options.

    Amazon returns a feedId value.

  4. Periodically call the getFeed (opens new window) operation, specifying the feedId value from step 3, until the feed moves into one of the following terminal states: DONE, CANCELLED, or FATAL. When the feed moves into the DONE state, proceed to Step 5.

    Amazon returns the resultFeedDocumentId value when the feed moves into the DONE state.

  5. Call the getFeedDocument (opens new window) operation. Use the feedDocumentId parameter to pass in the resultFeedDocumentId value from the previous step.

    Amazon returns the feedDocumentId value, a URL for downloading the feed processing report, and the encryption details.

  6. Download and decrypt the feed processing report.

  7. Check the feed processing report for errors generated during feed processing. If there are errors, correct them and submit the corrected feed, starting at step 1. If there are no errors, your feed submission was successful.

For more details about submitting a feed, see Tutorial: Submit a feed.

# Terminology

  1. Cipher block chaining. Cipher block chaining is an algorithm that uses a block cipher to provide information security such as confidentiality or authenticity. This algorithm uses an initialization vector and a key to encrypt the data.

  2. S3 presigned URL. A URL for an AWS S3 bucket to which you can upload an object without AWS security credentials or permissions. You get an S3 presigned URL in Step 1. Create a feed document and Step 5. Get information for retrieving the feed processing report.

# Tutorial: Submit a feed

This tutorial shows you how to submit a feed, check the status of feed processing, and verify that your feed submission was successful. The tutorial contains Java code samples that can help you with tasks such as encrypting and uploading a feed and downloading and decrypting a feed processing report. You can use the principles demonstrated in these code samples to guide you in accomplishing these tasks using other programming languages.

Prerequisites

To complete this tutorial, you will need:

  1. A feed to submit. See feedType values (opens new window) for a list of available feed types.

  2. Authorization from the seller for whom you are making calls. See the Selling Partner API Developer Guide (opens new window) for more information.

  3. A working Java Development Kit (JDK) installation, including the javax.crypto library.

  4. The Selling Partner API Documents Helper (opens new window).

  5. An understanding of client-side encryption using the cipher block chaining (CBC). For definitions, see Terminology (opens new window).

# Step 1. Create a feed document

Call the createFeedDocument operation to create a feed document.

  1. Call the createFeedDocument (opens new window) operation, passing the following parameter:

Body parameter:

Name Description Required
contentType

The content type of the feed. Amazon recommends UTF-8 character encoding.

Important. Use this contentType value in Step 2. Encrypt and upload the feed data. Otherwise your feed data upload will fail.

Type: string

Yes

Request example:

POST https://sellingpartnerapi-na.amazon.com/feeds/2020-09-04/documents
{
  "contentType":"text/tab-separated-values; charset=UTF-8"
}
1
2
3
4

Response

A successful response includes the following:

Name Description Required
feedDocumentId

The identifier of the feed document.

Type: string

Yes
url

The presigned URL for uploading the feed contents. This URL expires after 5 minutes.

Type: string

Yes
encryptionDetails

Encryption details for required client-side encryption of document contents.

Type: FeedDocumentEncryptionDetails

Yes

Response example:

{
  "payload":
  {
    "feedDocumentId":"amzn1.tortuga.3.920614b0-fc4c-4393-b0d9-fff175300000.T29XK4YL08B2VM",
    "url":"https://tortuga-prod-na.s3.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.920614b0-fc4c-4393-b0d9-fff175300000.T29XK4YL08B2VM?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200919T035824Z&X-Amz-SignedHeaders=<headers>&X-Amz-Expires=300&X-Amz-Credential=<credential>&X-Amz-Signature=<signature>",
    "encryptionDetails":
    {
      "standard":"AES",
      "initializationVector":"kF3bZt0FSv6JQEimfEJD8g==",
      "key":"5EZo/P06OGF0UAy8QuOnMIaQbkAvYBru6EGsFvK8wJ2="
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
  1. Save the following values:

# Step 2. Encrypt and upload the feed data

You can encrypt and upload feed data using the information returned in the previous step. The following sample code, along with the classes provided in the Selling Partner API (SP-API) Documents Helper (opens new window), can help. You can also use the principles demonstrated in the sample code and in the SP-API Documents Helper to guide you in building applications in other programming languages.

The sample code has methods for creating an input stream from a string and creating a piped input stream.

To create an input stream from a string

  • Use the following as input for the sample code:

    • Your feed data is input to the ByteArrayInputStream class.

    • The key, initializationVector, and url values from the previous step are arguments for the key, initializationVector, and url parameters of the encryptAndUpload_fromString method of the UploadExample class.

To create a piped input stream

  • Use the following as input for the sample code:

    • Your feed data is input to the PipedInputStream by way of its connection to the PipedOutputStream.

    • The key, initializationVector, and url values from the previous step are arguments for the key, initializationVector, and url parameters of the encryptAndUpload_fromPipedInputStream method of the UploadExample class.

# Encrypt and upload sample code (Java)

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;

import com.amazon.spapi.documents.UploadHelper;
import com.amazon.spapi.documents.UploadSpecification;
import com.amazon.spapi.documents.exception.CryptoException;
import com.amazon.spapi.documents.exception.HttpResponseException;
import com.amazon.spapi.documents.impl.AESCryptoStreamFactory;

/* We want to maintain encryption at rest, so do not write unencrypted data to disk.  This is bad:
InputStream source = new FileInputStream(new File("/path/to/myFeed.xml"));

Instead, if your data can fit in memory, you can create an InputStream from a String (see encryptAndUpload_fromString()).
Otherwise, you can pipe data into an InputStream using Piped streams (see encryptAndUpload_fromPipedInputStream()).
 */
public class UploadExample {
  private final UploadHelper uploadHelper = new UploadHelper.Builder().build();

  // key, initializationVector, and url are returned by the createFeedDocument operation.
  public void encryptAndUpload_fromString(String key, String initializationVector, String url) {
    AESCryptoStreamFactory aesCryptoStreamFactory =
      new AESCryptoStreamFactory.Builder(key, initializationVector)
      .build();

    // This contentType must be the same value that was provided to createFeedDocument.
    String contentType = String.format("text/plain; charset=%s", StandardCharsets.UTF_8);

    // The character set must be the same one that is specified in contentType.
    try
      (InputStream source = new ByteArrayInputStream("my feed data".getBytes(StandardCharsets.UTF_8))) {
        UploadSpecification uploadSpec =
          new UploadSpecification.Builder(contentType, aesCryptoStreamFactory, source, url)
          .build();

        uploadHelper.upload(uploadSpec);
      }
    catch (CryptoException | HttpResponseException | IOException e) {
      // Handle exception.
    }
  }

  // key, initializationVector, and url are returned from createFeedDocument.
  public void encryptAndUpload_fromPipedInputStream(String key, String initializationVector, String url) {
    AESCryptoStreamFactory aesCryptoStreamFactory =
      new AESCryptoStreamFactory.Builder(key, initializationVector)
      .build();

    // This contentType must be the same value that was provided to createFeedDocument.
    String contentType = String.format("text/plain; charset=%s", StandardCharsets.UTF_8);

    try
      (PipedInputStream source = new PipedInputStream()) {
        new Thread(
          new Runnable() {
          public void run() {
            try
              (PipedOutputStream feedContents = new PipedOutputStream(source)) {
                // The character set must be the same one that is specified in contentType.
                feedContents.write("my feed data\n".getBytes(StandardCharsets.UTF_8));
                feedContents.write("more feed data".getBytes(StandardCharsets.UTF_8));
              }
            catch (IOException e) {
              // Handle exception.
            }
          }
        }).start();

        UploadSpecification uploadSpec =
          new UploadSpecification.Builder(contentType, aesCryptoStreamFactory, source, url)
          .build();

        uploadHelper.upload(uploadSpec);
      }
    catch (CryptoException | HttpResponseException | IOException e) {
      // Handle exception.
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

# Step 3. Create a feed

Call the createFeed operation to specify the feed document identifier, the feed type, the marketplaces that you want the feed to be applied to, and any optional parameters that you want.

  1. Call the createFeed (opens new window) operation, passing the following parameters:

Body parameters:

Name Description Required
feedType

The type of feed that you are submitting. For more information, see feedType values.

Type: string

Yes
marketplaceIds

A list of identifiers for marketplaces that you want the feed to be applied to.

Type: < string > array

Yes
inputFeedDocumentId

The document identifier returned by the createFeedDocument operation in Step 1. Create a feed document.

Type: string

Yes
feedOptions

Additional options to control the feed. These vary by feed type.

Type: string

No

Request example:

POST https://sellingpartnerapi-na.amazon.com/feeds/2020-09-04/feeds
{
  "feedType":"POST_PRODUCT_DATA",
  "marketplaceIds":[
    "ATVPDKIKX0DER",
    "A2EUQ1WTGCTBG2"
  ],
  "inputFeedDocumentId":"amzn1.tortuga.3.920614b0-fc4c-4393-b0d9-fff175300000.T29XK4YL08B2VM"
}
1
2
3
4
5
6
7
8
9

Request example for an Easy Ship order:

POST https://sellingpartnerapi-na.amazon.com/feeds/2020-09-04/feeds
{
  "feedType":"POST_EASYSHIP_DOCUMENTS",
  "marketplaceIds":["A21TJRUUN4KGV"],
  "feedOptions":
  {
    "AmazonOrderId":"902-3159896-1390916",
    "DocumentType":"ShippingLabel"
  },
  "inputFeedDocumentId":"amzn1.tortuga.3.06438a22-2b6f-4138-a120-362c096d5e04.TKXDFQFUMYD86"
}
1
2
3
4
5
6
7
8
9
10
11

Response

A successful response includes the following element:

Name Description Required
feedId

The identifier for the feed. This identifier is unique only in combination with a seller ID.

Type: string

Yes

Response example:

{
  "payload":
  {
    "feedId": "23492394"
  }
}
1
2
3
4
5
6
  1. Save the feedId value. Pass this value in the getFeed operation in Step 4. Confirm feed processing.

# Step 4. Confirm feed processing

Confirm feed processing by periodically calling the getFeed operation until the feed moves into one of the following terminal states: DONE, CANCELLED, or FATAL. When the feed moves into the DONE state, proceed to Step 5. Get information for retrieving the feed processing report.

  1. Call the getFeed (opens new window) operation, passing the following parameter:

Path parameter:

Name Description Required
feedId

The identifier for the feed. Get this identifier from the result of the call to the createFeed operation in Step 3. Create a feed. This identifier is unique only in combination with a seller ID.

Type: string

Yes

Request example:

GET https://sellingpartnerapi-na.amazon.com/feeds/2020-09-04/feeds/23492394
1

Response

A successful response includes the following elements:

Name Description Required
feedId

The identifier for the feed document. This identifier is unique only in combination with a seller ID.

Type: string

Yes
feedType

The feed type.

Type: string

Yes
marketplaceIds

A list of identifiers for the marketplaces that the feed is applied to.

Type: < string > array

No
createdTime

The date and time when the feed was created, in ISO 8601 date time format.

Type: string (date-time)

Yes
processingStatus

The processing status of the feed.

Type: ProcessingStatus

Yes
processingStartTime

The date and time when feed processing started, in ISO 8601 date time format.

Type: string (date-time)

No
processingEndTime

The date and time when feed processing completed, in ISO 8601 date time format.

Type: string (date-time)

No
resultFeedDocumentId

The identifier for the feed document. This identifier is unique only in combination with a seller ID.

Type: string

No

Response Example:

{
  "payload":
  {
    "processingEndTime":"2020-08-10T16:56:55+00:00",
    "processingStatus":"DONE",
    "marketplaceIds":[
      "ATVPDKIKX0DER"
    ],
    "feedId":"23492394",
    "feedType":"POST_PRODUCT_DATA",
    "createdTime":"2020-08-10T16:55:32+00:00",
    "processingStartTime":"2020-08-10T16:55:40+00:00",
    "resultFeedDocumentId":"amzn1.tortuga.3.ed4cd0d8-447b-4c22-96b5-52da8ace1207.T3YUVYPGKE9BMY"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. Check the value of the processingStatus attribute.

    • If processingStatus is IN_QUEUE or IN_PROGRESS, feed processing is not yet complete. Retry the getFeed operation until processingStatus reaches one of the following terminal states: DONE, CANCELLED, or FATAL.

    • If processingStatus is DONE, feed processing is complete. Go to Step 5. Get information for retrieving the feed processing report.

    • If processingStatus is CANCELLED, the feed was cancelled before it started processing. If you want to submit the feed again, start again at Step 1. Create a feed document.

    • If processingStatus is FATAL, the feed was aborted due to a fatal error. Some, none, or all of the operations within the feed might have completed successfully. In some (but not all) cases Amazon generates a feed processing report. If Amazon generates a report, it could be in a different format from a feed processing report for a successfully completed feed. Go to Step 5. Get information for retrieving the feed processing report to attempt to retrieve a feed processing report. In rare cases Amazon might abort a feed for reasons unrelated to the feed. If you can find no errors in the feed to correct, try submitting the feed again.

Note: The getFeed operation only serves information for feed requests that were created within the last 90 days.

# Step 5. Get information for retrieving the feed processing report

The feed processing report indicates which records in the feed that you submitted were successful and which records generated errors. In this step you get a presigned URL for downloading the feed processing report as well as the information required to decrypt the document's contents.

  1. Call the getFeedDocument (opens new window) operation, passing the following parameter:

Path parameter:

Name Description Required
feedDocumentId

The identifier of the feed document. Use the resultFeedDocumentId value returned in Step 4. Confirm feed processing.

Type: string

Yes

Request example:

GET https://sellingpartnerapi-na.amazon.com/feeds/2020-09-04/documents/amzn1.tortuga.3.ed4cd0d8-447b-4c22-96b5-52da8ace1207.T3YUVYPGKE9BMY
1

Response

A successful response includes the following elements:

Name Description Required
feedDocumentId

The identifier for the feed document. This identifier is unique only in combination with a seller ID.

Type: string

Yes
url

A presigned URL for the feed document. This URL expires after 5 minutes.

Type: string

Yes
encryptionDetails

Encryption details for required client-side decryption of document contents.

Type: FeedDocumentEncryptionDetails

Yes
compressionAlgorithm

If present, the feed document contents are compressed using the indicated algorithm.

Type: CompressionAlgorithm

No

Response example:

{
  "payload":
  {
    "feedDocumentId":"amzn1.tortuga.3.ed4cd0d8-447b-4c22-96b5-52da8ace1207.T3YUVYPGKE9BMY",
    "url":"https://tortuga-prod-na.s3.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.920614b0-fc4c-4393-b0d9-fff175300000.T29XK4YL08B2VM?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200919T035824Z&X-Amz-SignedHeaders=<headers>&X-Amz-Expires=300&X-Amz-Credential=<credential>&X-Amz-Signature=<signature>",
    "encryptionDetails":
    {
      "standard":"AES",
      "initializationVector":"kF3bZt0FSv6JQEimfEJD8g==",
      "key":"5EZo/P06OGF0UAy8QuOnMIaQbkAvYBru6EGsFvK8wJ2="
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
  1. Save the initializationVector, key, and url values to pass in Step 6. Download and decrypt the feed processing report.

# Step 6. Download and decrypt the feed processing report

You can download and decrypt the feed processing report using the information returned in the previous step. The following Java sample code along with the classes provided in the Selling Partner API (SP-API) Documents Helper (opens new window) can help. You can also use the principles demonstrated in the Java sample code and in the SP-API Documents Helper to guide you in building applications in other programming languages.

  1. Use the following as inputs for the sample code:

    • The key, initializationVector, url, and optional compressionAlgorithm values from the previous step are arguments for the key, initializationVector, url, and compressionAlgorithm parameters of the downloadAndDecrypt method of the DownloadExample class.

Note: It's the developer's responsibility to always maintain encryption at rest. Unencrypted feed processing report content should never be stored on disk, even temporarily, because feed processing reports can contain sensitive information. The sample code that we provide demonstrates this principle.

# Download and decrypt sample code (Java)

// DownloadExample.java
import java.io.BufferedReader;
import java.io.IOException;
 
import com.amazon.spapi.documents.CompressionAlgorithm;
import com.amazon.spapi.documents.DownloadBundle;
import com.amazon.spapi.documents.DownloadHelper;
import com.amazon.spapi.documents.DownloadSpecification;
import com.amazon.spapi.documents.exception.CryptoException;
import com.amazon.spapi.documents.exception.HttpResponseException;
import com.amazon.spapi.documents.exception.MissingCharsetException;
import com.amazon.spapi.documents.impl.AESCryptoStreamFactory;
 
public class DownloadExample {
  final DownloadHelper downloadHelper = new DownloadHelper.Builder().build();
 
  // key, initializationVector, url, and compressionAlgorithm are returned by the getFeedDocument operation.
  public void downloadAndDecrypt(String key, String initializationVector, String url, String compressionAlgorithm) {
    AESCryptoStreamFactory aesCryptoStreamFactory =
      new AESCryptoStreamFactory.Builder(key, initializationVector).build();
 
    DownloadSpecification downloadSpec = new DownloadSpecification.Builder(aesCryptoStreamFactory, url)
      .withCompressionAlgorithm(CompressionAlgorithm.fromEquivalent(compressionAlgorithm))
      .build();
 
    try (DownloadBundle downloadBundle = downloadHelper.download(downloadSpec)) {
      // This example assumes that the downloaded file has a charset in the content type, e.g. 
      // text/plain; charset=UTF-8
      try (BufferedReader reader = downloadBundle.newBufferedReader()) {
        String line;
        do {
          line = reader.readLine();
          // Process the decrypted line.
        } while (line != null);
      }
    } 
    catch (CryptoException | HttpResponseException | IOException | MissingCharsetException e) {
        // Handle exception.
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# Step 7. Check the feed processing report for errors

Check the feed processing report for errors generated during processing. If there are no errors, your feed submission is complete. If there are errors, correct them and submit the corrected feed, starting at Step 1. Create a feed document. Repeat the process until there are no errors in the feed processing report.

# Best practices

For best practices using the Feeds API, refer to Feeds API Best Practices (opens new window).