title: Amazon MWS SubmitFeed Content-MD5 HTTP header did not match the Content-MD5 calculated by Amazon
body: <p>I know this question is not new but all the solution I get for this are in PHP or my issue is different from them.</p>
  
  <p>I am using MWS feed API to submit flat file for Price and Quantity Updates and always get the following error:</p>
  
  <blockquote>
    <p>the Content-MD5 HTTP header you passed for your feed did not match the
    Content-MD5 we calculated for your feed</p>
  </blockquote>
  
  <hr>
  
  <p><strong>I would like to ask 3 questions here:-</strong></p>
  
  <ol>
  <li><p>ContentMD5Value parameter is optional as given in doc, but if i not passed that than it will say that you must enter ContentMD5Value.</p></li>
  <li><p>As in doc the <code>ContentFeed</code> which we are given to Amazon. Amazon create <code>contentMD5</code> for that file and then compares that <code>contentMD5</code> value with the <code>contentMD5</code> value we send to Amazon.<br>
  If both match then OK, otherwise it will throw an error. But if suppose I will not send the file then also the same errors come that MD5 does not match. How is that possible? Which file are they calculating the MD5 for? Because I haven't send the file in <code>ContentFeed</code>.</p></li>
  <li><p>If I send the <code>contentMD5</code> in a header as well as parameter and sending the <code>ContentFeed</code> in body, I still get the error.</p></li>
  </ol>
  
  <p>Note:- I am sending the <code>contentMD5</code> in a header as well as in a parameters in form using request module and also calculating the signature with that and then pass the <code>contentFeed</code> in body.</p>
  
  <p>I am using JavaScript (Meteor), I calculate the md5 using the  <code>crpyto</code> module.<br>
  First, I think that my md5 is wrong but then I tried with an online website that will give me the md5 for a file the md5.</p>
  
  <p>for my file is:</p>
  
  <blockquote>
    <p>MD5 value:   d90e9cfde58aeba7ea7385b6d77a1f1e<br>
       Base64Encodevalue: ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=</p>
  </blockquote>
  
  <p>The flat file I downloaded from for Price and Quantity Updates:-</p>
  
  <blockquote>
    <p><a href="https://sellercentral.amazon.in/gp/help/13461?ie=UTF8&amp;Version=1&amp;entries=0&amp;" rel="nofollow noreferrer">https://sellercentral.amazon.in/gp/help/13461?ie=UTF8&amp;Version=1&amp;entries=0&amp;</a></p>
  </blockquote>
  
  <p>I calculated the signature also by giving <code>ContentMD5Value</code> while calculating the signature.</p>
  
  <blockquote>
    <p>FeedType:'_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'</p>
  </blockquote>
  
  <p>As, I read documentation for that I passed the MD5-header in headers and also send as parameter.</p>
  
  <p>Amazon doc says:</p>
  
  <blockquote>
    <p>Previously, Amazon MWS accepted the MD5 hash as a Content-MD5 header
    instead of a parameter. Passing it as a parameter ensures that the MD5
    value is part of the method signature, which prevents anyone on the
    network from tampering with the feed content.</p>
    
    <p>Amazon MWS will still accept a Content-MD5 header whether or not a
    ContentMD5Value parameter is included. If both a header and parameter
    are used, and they do not match, you will receive an
    InvalidParameterValue error.</p>
  </blockquote>
  
  <p><strong>I am using the <code>request</code> module for http requests.</strong></p>
  
  <p>I am passing all the required keys, seller id, etc. in form of request module and passing the <code>FeedContent</code> in body.</p>
  
  <p><strong>I tried sending the file as follows:</strong></p>
  
  <p><strong>Method for submitFeed is:-</strong></p>
  
  <pre><code>submitFeed : function(){
      console.log("submitFeedAPI running..");
      app  = mwsReport({auth: {sellerId:'A4TUFSCXD64V3', accessKeyId:'AKIAJBU3FTBCJUIZWF', secretKey:'Eug7ZbaLljtrnGKGFT/DTH23HJ' }, marketplace: 'IN'});
      app.submitFeedsAPI({FeedType:'_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'},Meteor.bindEnvironment(function(err,response){
          if(err){
              console.log("error in submit feed...")
              console.log(err)
          }
          else{
              console.log("suuccess submit feed....")
              console.log(response);
          }
      }))
  </code></pre>
  
  <p><strong>Method that call Amazon submitFeedAPI is:-</strong></p>
  
  <pre><code>    var submitFeedsAPI =  function(options, callback){
          console.log("submitFeedsAPI running...");
      var fileReadStream = fs.createReadStream('/home/parveen/Downloads/test/testting.txt');
          var contentMD5Value = crypto.createHash('md5').update(file).digest('base64');
  
      var reqForm = {query: {"Action": "SubmitFeed", "MarketplaceId": mpList[mpCur].id, "FeedType":options.FeedType,"PurgeAndReplace":false,"ContentMD5Value":contentMD5Value}}; 
              mwsReqProcessor(reqForm, 'submitFeedsAPI', "submitFeedsAPIResponse", "submitFeedsAPIResult", "mwsprod-0000",false,file, callback);
      }
  
  
  also try
  
      var fileReadStream = fs.createReadStream('/home/parveen/Downloads/test/testting.txt');
      var base64Contents = fileReadStream.toString('base64');
      var contentMD5Value = crypto.createHash('md5').update(base64Contents).digest('base64');
  </code></pre>
  
  <p><strong>mwsReqProcessor function is as below:-</strong></p>
  
  <pre><code> mwsReqProcessor = function mwsReqProcessor(reqForm, name, responseKey, resultKey, errorCode,reportFlag,file, callback) {
  
          reqOpt = {
              url: mwsReqUrl,
              method: 'POST',
              timeout: 40000,
              body:{FeedContent: fs.readFileSync('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt')},
              json:true,
              form: null,
              headers: {
                  // 'Transfer-Encoding': 'chunked',
                  //'Content-Type': 'text/xml',
                 // 'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
                  // 'Content-Type': 'text/xml; charset=iso-8859-1'
                  'Content-Type':'text/tab-separated-values;charset=UTF-8'
              },
          }
          reqOpt.form = mwsReqQryGen(reqForm);
          var r = request(reqOpt, function (err, res, body){
              console.log(err)
              console.log(res)
          })
          // var form  = r.form();
          //form.append('FeedContent',fs.createReadStream('/home/parveen/feedContent//File/Flat.File.PriceInventory.in.txt'))
      }
  </code></pre>
  
  <p><strong>Method for mwsReqQryGen generation:-</strong></p>
  
  <pre><code>mwsReqQryGen = function mwsReqQryGen(options) {
      var method     = (options &amp;&amp; options.method) ? ('' + options.method) : 'POST',
          host       = (options &amp;&amp; options.host)   ? ('' + options.host)   : mwsReqHost,
          path       = (options &amp;&amp; options.path)   ? ('' + options.path)   : mwsReqPath,
          query      = (options &amp;&amp; options.query)  ? options.query         : null,
  
  
          returnData = {
            "AWSAccessKeyId": authInfo.accessKeyId,
            "SellerId": authInfo.sellerId,
            "SignatureMethod": "HmacSHA256",
            "SignatureVersion": "2",
            "Timestamp": new Date().toISOString(),
             "Version":"2009-01-01",
          },
          key;
  
      if(query &amp;&amp; typeof query === "object")
        for(key in query)
          if(query.hasOwnProperty(key)) returnData[key] = ('' + query[key]);
  
      if(authInfo.secretKey &amp;&amp; method &amp;&amp; host &amp;&amp; path) {
  
        // Sort query parameters
        var keys = [],
            qry  = {};
  
        for(key in returnData)
          if(returnData.hasOwnProperty(key)) keys.push(key);
  
        keys = keys.sort();
        for(key in keys)
          if(keys.hasOwnProperty(key)) qry[keys[key]] = returnData[keys[key]];
        var sign = [method, host, path, qs.stringify(qry)].join("\n");
        console.log("..................................................")
        returnData.Signature = mwsReqSignGen(sign);
  
      }
  //console.log(returnData); // for debug
  
  return returnData;
  </code></pre>
  
  <p>};</p>
  
  <p>I also tried with following:-</p>
  
  <pre><code>reqOpt = {
      url: mwsReqUrl,
      method: 'POST',
      timeout: 40000,
      json:true,
      form: null,
      body:  {FeedContent: fs.createReadStream('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt')},
      headers: {
          // 'Transfer-Encoding': 'chunked',
          //'Content-Type': 'text/xml',
         // 'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
          //   'Content-Type': 'text/xml; charset=iso-8859-1'
      },
  }
  </code></pre>
  
  <p>I also tried without JSON and directly send the file read stream in the
  body, i.e:</p>
  
  <pre><code>reqOpt = {
      url: mwsReqUrl,
      method: 'POST',
      timeout: 40000,
      form: null,
      body:  fs.createReadStream('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt'),
      headers: {
          // 'Transfer-Encoding': 'chunked',
          //'Content-Type': 'text/xml',
       //   'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
          //   'Content-Type': 'text/xml; charset=iso-8859-1'
      },
  }
  </code></pre>
  
  <p>But same error comes every time:</p>
  
  <blockquote>
    <p>the Content-MD5 HTTP header you passed for your feed did not match the
    Content-MD5 we calculated for your feed</p>
  </blockquote>
  
  <p>I want to know where I am doing wrong or what is the right way to submit feed API and sending the file using request module.</p>
  
  <p>I also tried with the code given on MWS to generate the MD5 but same
  error occurred each time.</p>
  
  <p><strong>My .txt file as follows:</strong></p>
  
  <pre>
  sku price   quantity
  TP-T2-00-M      2
  </pre>
  
  <p>Any help is much appreciated</p>