 <p>You will have to <code>ksort()</code> your params before you pass them here:</p> <pre><code>foreach(array_keys($params) as $key) { $url_parts[] = $key . "=" . str_replace('%7E', '~', rawurlencode($params[$key])); } </code></pre> <p>e.g.</p> <pre><code>$params = array( 'AWSAccessKeyId' =&gt; "MY_AWS_KEY", 'Action' =&gt; "SubmitFeed", 'SellerId' =&gt; "MY_SELLER_ID", 'FeedType' =&gt; "_POST_PRODUCT_DATA_", 'SignatureMethod' =&gt; "HmacSHA256", 'SignatureVersion' =&gt; "2", 'Timestamp'=&gt; $timestamp, 'Version'=&gt; "2009-01-01", 'MarketplaceIdList.Id.1' =&gt; "MY_MARKETPLACE_ID", 'PurgeAndReplace'=&gt;'false' ); $secret = 'MY_SECRET_KEY'; $url_parts = array(); ksort($params); foreach(array_keys($params) as $key) { $url_parts[] = $key . "=" . str_replace('%7E', '~', rawurlencode($params[$key])); } </code></pre> <p>I'm not entirely sure about the string you are signing, you should try it with this (adding /Feeds/2009-01-01 to it):</p> <pre><code>"POST\nmws-eu.amazonservices.com\n/Feeds/2009-01-01\n" . $url_string </code></pre> <p>Also, Amazon expects a <code>SellerId</code> for the <code>_POST_PRODUCT_DATA_</code> operation, not <code>Merchant</code>.</p> <p>I suggest you to use mws-eu-amazonservices.com instead of the co.uk one, you can use this for all the european marketplaces and don't need to change it for each. As a sidenote:</p> <p>Amazon doesn't really report the correct error. The error you are getting can also occur if only SellerId is Merchant like above, or anything different that has nothing to do with what you are trying to do. </p>