Index: /changelog
===================================================================
--- /changelog	(revision 7755)
+++ /changelog	(revision 7756)
@@ -382,2 +382,5 @@
 - Bugfix: Deinstallation von Produkten lÃ¶scht abhÃ€ngigkeiten (Produktartikelwerte, Varianten)
 
+#4.2.6
+- Bugfix: Falsche Bilder beim hinzufÃŒgen von Bilder im Warenkorblayer (Theme)
+
Index: /controller/wpsg_AdminController.class.php
===================================================================
--- /controller/wpsg_AdminController.class.php	(revision 7755)
+++ /controller/wpsg_AdminController.class.php	(revision 7756)
@@ -2271,11 +2271,13 @@
 	
 								$bExists = $this->db->fetchOne("SELECT `option_id` FROM `".$wpdb->prefix."options` WHERE `option_name` = '".wpsg_q(strval($a->option_name))."' ");
-	
+
+								$option_name = $a->option_name;
+								$option_value = $a->option_value;
+
 								// Wenn eine Seite importiert wird,
-								if(strpos(wpsg_q(strval($a->option_name)), "wpsg_page") !== false && wpsg_isSizedInt(wpsg_q(strval($a->option_value))))
-								{
+								if (strpos($option_name, "wpsg_page") !== false && wpsg_isSizedInt($option_value)) {
+
 									// welche in der momentanen Instanz nicht existiert
-									if(!get_post_status(wpsg_q(strval($a->option_value))))
-									{
+									if (!get_post_status($option_value)) {
 	
 										$this->shop->addBackendError(wpsg_translate(__('Die importierte Seite mit der ID #1# ist noch nicht angelegt worden. Daher wird sie auf "Keine Zuordnung" gestellt.', "wpng"), wpsg_q(strval($a->option_value))));
Index: /controller/wpsg_ShopController.class.php
===================================================================
--- /controller/wpsg_ShopController.class.php	(revision 7755)
+++ /controller/wpsg_ShopController.class.php	(revision 7756)
@@ -690,5 +690,5 @@
 		public function checkEscape() {
 
-			if (strlen($_GET['wpsg_quotecheck']) > 7 || get_magic_quotes_gpc()) {
+			if (strlen($_GET['wpsg_quotecheck']) > 7 /*|| get_magic_quotes_gpc()*/) {
 
 				$_POST      = array_map('stripslashes_deep', $_POST);
@@ -2196,5 +2196,5 @@
 				
 				if (isset($_REQUEST['wpsg']['produkt_id']) && ($_REQUEST['wpsg']['produkt_id'] == $produkt['product_id'])) { $produkt['product_id'] = $_REQUEST['wpsg']['produkt_id']; }
-				if (isset($_REQUEST['wpsg']['product_key'])) { $produkt['product_key'] = $_REQUEST['wpsg']['product_key']; }
+                if (isset($_REQUEST['wpsg']['product_key']) && $_REQUEST['wpsg']['produkt_id'] == $produkt['product_id']) { $produkt['product_key'] = $_REQUEST['wpsg']['product_key']; }
 			    
 			}
@@ -2961,7 +2961,5 @@
 				if (get_locale() != $this->getDefaultLanguageLocale()) return true;
 
-			}
-			else
-			{
+			} else if (is_array($q_config)) {
 
 				// qTranslate
@@ -3241,4 +3239,6 @@
 				]
 			];
+
+            $this->checkCustomerPreset();
 			
 			$this->callMods('addShipping', array(&$this->arShipping));
Index: /model/wpsg_customer.class.php
===================================================================
--- /model/wpsg_customer.class.php	(revision 7755)
+++ /model/wpsg_customer.class.php	(revision 7756)
@@ -153,5 +153,5 @@
 			$arAnrede = explode('|', $this->shop->get_option('wpsg_admin_pflicht')['anrede_auswahl']);
 			if ($title < 0) return '';
-			else return $arAnrede[$title];
+			else return @$arAnrede[$title];
 			
 		} // public function getTitle()
Index: /model/wpsg_order.class.php
===================================================================
--- /model/wpsg_order.class.php	(revision 7755)
+++ /model/wpsg_order.class.php	(revision 7756)
@@ -30,11 +30,16 @@
 			@$this->data = &$this->shop->cache->loadOrder($order_id, true);
 			@$this->customer = &$this->shop->cache->loadCustomerObject($this->data['k_id']);
-			$this->bShippingAdress = $this->shop->callMod('wpsg_mod_shippingadress', 'check_different_shippingadress', array($this->data['k_id'], $order_id));
-				
-			if (isset($this->data['id']) && ($this->data['id'] != $order_id)) throw new \wpsg\Exception(__('Die Daten eines Bestellobjekts konnten nicht geladen werden ', 'wpsg'));
-				
-			if (wpsg_isSizedInt($this->data['adress_id'])) $this->adress_data = $this->db->fetchRow("SELECT * FROM `".WPSG_TBL_ADRESS."` WHERE `id` = '".wpsg_q($this->data['adress_id'])."' ");
-			if (wpsg_isSizedInt($this->data['shipping_adress_id'])) $this->shipping_adress_data = $this->db->fetchRow("SELECT * FROM `".WPSG_TBL_ADRESS."` WHERE `id` = '".wpsg_q($this->data['shipping_adress_id'])."' ");
-	 			
+
+			if (is_array($this->data)) {
+
+			    $this->bShippingAdress = $this->shop->callMod('wpsg_mod_shippingadress', 'check_different_shippingadress', array($this->data['k_id'], $order_id));
+				
+			    if (isset($this->data['id']) && ($this->data['id'] != $order_id)) throw new \wpsg\Exception(__('Die Daten eines Bestellobjekts konnten nicht geladen werden ', 'wpsg'));
+				
+			    if (wpsg_isSizedInt($this->data['adress_id'])) $this->adress_data = $this->db->fetchRow("SELECT * FROM `".WPSG_TBL_ADRESS."` WHERE `id` = '".wpsg_q($this->data['adress_id'])."' ");
+			    if (wpsg_isSizedInt($this->data['shipping_adress_id'])) $this->shipping_adress_data = $this->db->fetchRow("SELECT * FROM `".WPSG_TBL_ADRESS."` WHERE `id` = '".wpsg_q($this->data['shipping_adress_id'])."' ");
+
+            }
+
 			return true;
 			
Index: /mods/mod_amazon/PayWithAmazon/Client.php
===================================================================
--- /mods/mod_amazon/PayWithAmazon/Client.php	(revision 7755)
+++ /mods/mod_amazon/PayWithAmazon/Client.php	(revision 7756)
@@ -1,8 +1,8 @@
 <?php
-namespace PayWithAmazon;
+namespace AmazonPay;
 
 /* Class Client
  * Takes configuration information
- * Makes API calls to MWS for Pay With Amazon
+ * Makes API calls to MWS for Amazon Pay
  * returns Response Object
  */
@@ -10,11 +10,20 @@
 require_once 'ResponseParser.php';
 require_once 'HttpCurl.php';
-require_once 'Interface.php';
+require_once 'ClientInterface.php';
 require_once 'Regions.php';
-
-class Client implements ClientInterface
+if (!interface_exists('\Psr\Log\LoggerAwareInterface')) {
+    require_once(__DIR__.'/../Psr/Log/LoggerAwareInterface.php');
+}
+
+if (!interface_exists('\Psr\Log\LoggerInterface')) {
+    require_once(__DIR__.'/../Psr/Log/LoggerInterface.php');
+}
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+
+class Client implements ClientInterface, LoggerAwareInterface
 {
-    const MWS_CLIENT_VERSION = '1.0.0';
-    const SERVICE_VERSION = '2013-01-01';
+    const SDK_VERSION = '3.6.0';
+    const MWS_VERSION = '2013-01-01';
     const MAX_ERROR_RETRY = 3;
 
@@ -25,21 +34,24 @@
     private $mwsEndpointUrl = null;
     private $profileEndpoint = null;
-    private $config = array('merchant_id' 	   => null,
-			    'secret_key' 	   => null,
-			    'access_key' 	   => null,
-			    'region' 		   => null,
-			    'currency_code' 	   => null,
-			    'sandbox' 		   => false,
-			    'platform_id' 	   => null,
-			    'cabundle_file' 	   => null,
-			    'application_name'     => null,
-			    'application_version'  => null,
-			    'proxy_host' 	   => null,
-			    'proxy_port' 	   => -1,
-			    'proxy_username' 	   => null,
-			    'proxy_password' 	   => null,
-			    'client_id' 	   => null,
-			    'handle_throttle' 	   => true
-			    );
+    private $config = array(
+                'merchant_id'          => null,
+                'secret_key'           => null,
+                'access_key'           => null,
+                'region'               => null,
+                'currency_code'        => null,
+                'sandbox'              => false,
+                'platform_id'          => null,
+                'cabundle_file'        => null,
+                'application_name'     => null,
+                'application_version'  => null,
+                'proxy_host'           => null,
+                'proxy_port'           => -1,
+                'proxy_username'       => null,
+                'proxy_password'       => null,
+                'client_id'            => null,
+                'app_id'               => null,
+                'handle_throttle'      => true,
+                'override_service_url' => null
+            );
 
     private $modePath = null;
@@ -51,6 +63,10 @@
     private $regionMappings;
 
+    // Implement a logging library that utilizes the PSR 3 logger interface
+    private $logger = null;
+
     // Boolean variable to check if the API call was a success
     public $success = false;
+
 
     /* Takes user configuration array from the user as input
@@ -58,8 +74,8 @@
      * Validates the user configuration array against existing config array
      */
-
     public function __construct($config = null)
     {
-	$this->getRegionUrls();
+        $this->getRegionUrls();
+
         if (!is_null($config)) {
 
@@ -67,8 +83,13 @@
                 $configArray = $config;
             } elseif (!is_array($config)) {
-		$configArray = $this->checkIfFileExists($config);
-	    }
-
-	    if (is_array($configArray)) {
+                $configArray = $this->checkIfFileExists($config);
+            }
+
+            // Invoke sandbox setter to throw exception if not Boolean datatype
+            if (!empty($configArray['sandbox'])) {
+                $this->setSandbox($configArray['sandbox']);
+            }
+
+            if (is_array($configArray)) {
                 $this->checkConfigKeys($configArray);
             } else {
@@ -76,39 +97,52 @@
             }
         } else {
-	    throw new \Exception('$config cannot be null.');
-	}
+            throw new \Exception('$config cannot be null.');
+        }
+    }
+
+
+    public function setLogger(LoggerInterface $logger = null) {
+        $this->logger = $logger;
     }
     
+
+    /* Helper function to log data within the Client */
+    private function logMessage($message) {
+        if ($this->logger) {
+            $this->logger->debug($message);
+        }
+    }
+    
+
     /* Get the Region specific properties from the Regions class.*/
-    
     private function getRegionUrls()
     {
-	$regionObject = new Regions();
-	$this->mwsServiceUrls = $regionObject->mwsServiceUrls;
-	$this->regionMappings = $regionObject->regionMappings;
-	$this->profileEndpointUrls = $regionObject->profileEndpointUrls;
-    }
+        $regionObject = new Regions();
+        $this->mwsServiceUrls = $regionObject->mwsServiceUrls;
+        $this->regionMappings = $regionObject->regionMappings;
+        $this->profileEndpointUrls = $regionObject->profileEndpointUrls;
+    }
+
 
     /* checkIfFileExists -  check if the JSON file exists in the path provided */
-
     private function checkIfFileExists($config)
     {
-	if(file_exists($config))
-	{
-	    $jsonString  = file_get_contents($config);
-	    $configArray = json_decode($jsonString, true);
-
-	    $jsonError = json_last_error();
-
-	    if ($jsonError != 0) {
-		$errorMsg = "Error with message - content is not in json format" . $this->getErrorMessageForJsonError($jsonError) . " " . $configArray;
-		throw new \Exception($errorMsg);
-	    }
-	} else {
-	    $errorMsg ='$config is not a Json File path or the Json File was not found in the path provided';
-	    throw new \Exception($errorMsg);
-	}
-	return $configArray;
-    }
+        if (file_exists($config)) {
+            $jsonString  = file_get_contents($config);
+            $configArray = json_decode($jsonString, true);
+
+            $jsonError = json_last_error();
+
+            if ($jsonError != 0) {
+                $errorMsg = "Error with message - content is not in json format" . $this->getErrorMessageForJsonError($jsonError) . " " . $configArray;
+                throw new \Exception($errorMsg);
+            }
+        } else {
+            $errorMsg ='$config is not a Json File path or the Json File was not found in the path provided';
+            throw new \Exception($errorMsg);
+        }
+        return $configArray;
+    }
+
 
     /* Checks if the keys of the input configuration matches the keys in the config array
@@ -116,9 +150,8 @@
      * strict case match is not performed
      */
-
     private function checkConfigKeys($config)
     {
         $config = array_change_key_case($config, CASE_LOWER);
-	$config = $this->trimArray($config);
+        $config = $this->trimArray($config);
 
         foreach ($config as $key => $value) {
@@ -127,8 +160,9 @@
             } else {
                 throw new \Exception('Key ' . $key . ' is either not part of the configuration or has incorrect Key name.
-				check the config array key names to match your key names of your config array', 1);
-            }
-        }
-    }
+                check the config array key names to match your key names of your config array', 1);
+            }
+        }
+    }
+
 
     /* Convert a json error code to a descriptive error message
@@ -138,5 +172,4 @@
      * @return string error message
      */
-
     private function getErrorMessageForJsonError($jsonError)
     {
@@ -160,8 +193,8 @@
     }
 
+
     /* Setter for sandbox
      * Sets the Boolean value for config['sandbox'] variable
      */
-
     public function setSandbox($value)
     {
@@ -169,12 +202,12 @@
             $this->config['sandbox'] = $value;
         } else {
-            throw new \Exception($value . ' is of type ' . gettype($value) . ' and should be a boolean value');
-        }
-    }
+            throw new \Exception('sandbox value ' . $value . ' is of type ' . gettype($value) . ' and should be a boolean value');
+        }
+    }
+
 
     /* Setter for config['client_id']
      * Sets the value for config['client_id'] variable
      */
-
     public function setClientId($value)
     {
@@ -185,4 +218,18 @@
         }
     }
+
+
+    /* Setter for config['app_id']
+     * Sets the value for config['app_id'] variable
+     */
+    public function setAppId($value)
+    {
+        if (!empty($value)) {
+            $this->config['app_id'] = $value;
+        } else {
+            throw new \Exception('setter value for app ID provided is empty');
+        }
+    }
+
 
     /* Setter for Proxy
@@ -193,9 +240,8 @@
      * @param $proxy['proxy_user_password'] - if your proxy required a password
      */
-
     public function setProxy($proxy)
     {
-	if (!empty($proxy['proxy_user_host']))
-	    $this->config['proxy_host'] = $proxy['proxy_user_host'];
+        if (!empty($proxy['proxy_user_host']))
+            $this->config['proxy_host'] = $proxy['proxy_user_host'];
 
         if (!empty($proxy['proxy_user_port']))
@@ -209,17 +255,17 @@
     }
 
+
     /* Setter for $mwsServiceUrl
      * Set the URL to which the post request has to be made for unit testing
      */
-
     public function setMwsServiceUrl($url)
     {
-	$this->mwsServiceUrl = $url;
-    }
+        $this->mwsServiceUrl = $url;
+    }
+
 
     /* Getter
      * Gets the value for the key if the key exists in config
      */
-
     public function __get($name)
     {
@@ -227,30 +273,31 @@
             return $this->config[strtolower($name)];
         } else {
-            throw new \Exception('Key ' . $name . ' is either not a part of the configuration array config or the' . $name . 'does not match the key name in the config array', 1);
-        }
-    }
+            throw new \Exception('Key ' . $name . ' is either not a part of the configuration array config or the ' . $name . ' does not match the key name in the config array', 1);
+        }
+    }
+
 
     /* Getter for parameters string
      * Gets the value for the parameters string for unit testing
      */
-
     public function getParameters()
     {
-	return trim($this->parameters);
+        return trim($this->parameters);
     }
     
+
     /* Trim the input Array key values */
-    
     private function trimArray($array)
     {
-	foreach ($array as $key => $value)
-	{
-	    if(!is_array($value) && $key!=='proxy_password')
-	    {
-		$array[$key] = trim($value);
-	    }
-	}
-	return $array;
-    }
+        foreach ($array as $key => $value) {
+            // Do not attemp to trim array variables, boolean variables, or the proxy password
+            // Trimming a boolean value (as a string) may not produce the expected output, so pass it through as-is
+            if (!is_array($value) && !is_bool($value) && $key !== 'proxy_password') {
+                $array[$key] = trim($value);
+            }
+        }
+        return $array;
+    }
+
 
     /* GetUserInfo convenience function - Returns user's profile information from Amazon using the access token returned by the Button widget.
@@ -259,5 +306,4 @@
      * @param $accessToken [String]
      */
-
     public function getUserInfo($accessToken)
     {
@@ -271,14 +317,17 @@
         // To make sure double encoding doesn't occur decode first and encode again.
         $accessToken = urldecode($accessToken);
-        $url 	     = $this->profileEndpoint . '/auth/o2/tokeninfo?access_token=' . urlEncode($accessToken);
+        $url          = $this->profileEndpoint . '/auth/o2/tokeninfo?access_token=' . $this->urlEncode($accessToken);
 
         $httpCurlRequest = new HttpCurl($this->config);
 
         $response = $httpCurlRequest->httpGet($url);
-        $data 	  = json_decode($response);
-
-        if ($data->aud != $this->config['client_id']) {
+        $data       = json_decode($response);
+
+        // Ensure that the Access Token matches either the supplied Client ID *or* the supplied App ID
+        // Web apps and Mobile apps will have different Client ID's but App ID should be the same
+        // As long as one of these matches, from a security perspective, we have done our due diligence
+        if (($data->aud != $this->config['client_id']) && ($data->app_id != $this->config['app_id'])) {
             // The access token does not belong to us
-            throw new \Exception('The Access token entered is incorrect');
+            throw new \Exception('The Access Token belongs to neither your Client ID nor App ID');
         }
 
@@ -288,5 +337,5 @@
 
         $httpCurlRequest->setAccessToken($accessToken);
-        $httpCurlRequest->setHttpHeader(true);
+        $httpCurlRequest->setHttpHeader();
         $response = $httpCurlRequest->httpGet($url);
 
@@ -294,4 +343,5 @@
         return $userInfo;
     }
+
 
     /* setParametersAndPost - sets the parameters array with non empty values from the requestParameters array sent to API calls.
@@ -299,67 +349,70 @@
      * If Provider Credit Reversal Details is present, values are set by setProviderCreditDetails
      */
-
     private function setParametersAndPost($parameters, $fieldMappings, $requestParameters)
     {
-	/* For loop to take all the non empty parameters in the $requestParameters and add it into the $parameters array,
-	 * if the keys are matched from $requestParameters array with the $fieldMappings array
-	 */
+        /* For loop to take all the non empty parameters in the $requestParameters and add it into the $parameters array,
+         * if the keys are matched from $requestParameters array with the $fieldMappings array
+         */
         foreach ($requestParameters as $param => $value) {
 
-	    if(!is_array($value)) {
-		$value = trim($value);
-	    }
-
-            if (array_key_exists($param, $fieldMappings) && $value!='') {
-
-		if(is_array($value)) {
-		    // If the parameter is a provider_credit_details or provider_credit_reversal_details, call the respective functions to set the values
-		    if($param === 'provider_credit_details') {
-			$parameters = $this->setProviderCreditDetails($parameters,$value);
-		    } elseif ($param === 'provider_credit_reversal_details') {
-			$parameters = $this->setProviderCreditReversalDetails($parameters,$value);
-		    }
-
-		} else{
-		    // For variables that are boolean values, strtolower them
-		    if($this->checkIfBool($value))
-		    {
-			$value = strtolower($value);
-		    }
-
-		    $parameters[$fieldMappings[$param]] = $value;
-		}
+            // Do not use trim on boolean values, or it will convert them to '0' or '1'
+            if (!is_array($value) && !is_bool($value)) {
+                $value = trim($value);
+            }
+
+            // Ensure that no unexpected type coercions have happened
+            if ($param === 'capture_now' || $param === 'confirm_now' || $param === 'inherit_shipping_address' || $param === 'request_payment_authorization') {
+                if (!is_bool($value)) {
+                    throw new \Exception($param . ' value ' . $value . ' is of type ' . gettype($value) . ' and should be a boolean value');
+                }
+            } elseif ($param === 'provider_credit_details' || $param === 'provider_credit_reversal_details' || $param === 'order_item_categories' || $param === 'notification_configuration_list') {
+                if (!is_array($value)) {
+                    throw new \Exception($param . ' value ' . $value . ' is of type ' . gettype($value) . ' and should be an array value');
+                }
+            }
+
+            // When checking for non-empty values, consider any boolean as non-empty
+            if (array_key_exists($param, $fieldMappings) && (is_bool($value) || $value!='')) {
+
+                if (is_array($value)) {
+                    // If the parameter is a provider_credit_details or provider_credit_reversal_details, call the respective functions to set the values
+                    if ($param === 'provider_credit_details') {
+                        $parameters = $this->setProviderCreditDetails($parameters, $value);
+                    } elseif ($param === 'provider_credit_reversal_details') {
+                        $parameters = $this->setProviderCreditReversalDetails($parameters, $value);
+                    } elseif ($param === 'order_item_categories') {
+                        $parameters = $this->setOrderItemCategories($parameters, $value);
+                    } elseif ($param == 'notification_configuration_list') {
+                        $parameters = $this->setNotificationConfigurationList($parameters, $value);
+                    }
+
+                } else {
+                    $parameters[$fieldMappings[$param]] = $value;
+                }
             }
         }
 
         $parameters = $this->setDefaultValues($parameters, $fieldMappings, $requestParameters);
-	$responseObject = $this->calculateSignatureAndPost($parameters);
-
-	return $responseObject;
-    }
-
-    /* checkIfBool - checks if the input is a boolean */
-    
-    private function checkIfBool($string)
-    {
-	$string = strtolower($string);
-	return in_array($string, array('true', 'false'));
-    }
+        $responseObject = $this->calculateSignatureAndPost($parameters);
+
+        return $responseObject;
+    }
+
 
     /* calculateSignatureAndPost - convert the Parameters array to string and curl POST the parameters to MWS */
-
     private function calculateSignatureAndPost($parameters)
     {
-	// Call the signature and Post function to perform the actions. Returns XML in array format
+        // Call the signature and Post function to perform the actions. Returns XML in array format
         $parametersString = $this->calculateSignatureAndParametersToString($parameters);
 
-	// POST using curl the String converted Parameters
-	$response = $this->invokePost($parametersString);
-
-	// Send this response as args to ResponseParser class which will return the object of the class.
+        // POST using curl the String converted Parameters
+        $response = $this->invokePost($parametersString);
+
+        // Send this response as args to ResponseParser class which will return the object of the class.
         $responseObject = new ResponseParser($response);
         return $responseObject;
     }
 
+
     /* If merchant_id is not set via the requestParameters array then it's taken from the config array
      *
@@ -369,5 +422,4 @@
      * else take the value from config array if set
      */
-
     private function setDefaultValues($parameters, $fieldMappings, $requestParameters)
     {
@@ -376,12 +428,13 @@
 
         if (array_key_exists('platform_id', $fieldMappings)) {
-	    if (empty($requestParameters['platform_id']) && !empty($this->config['platform_id']))
-            $parameters[$fieldMappings['platform_id']] = $this->config['platform_id'];
-	}
-
+            if (empty($requestParameters['platform_id']) && !empty($this->config['platform_id']))
+               $parameters[$fieldMappings['platform_id']] = $this->config['platform_id'];
+        }
         if (array_key_exists('currency_code', $fieldMappings)) {
             if (!empty($requestParameters['currency_code'])) {
-		$parameters[$fieldMappings['currency_code']] = strtoupper($requestParameters['currency_code']);
-            } else {
+                $parameters[$fieldMappings['currency_code']] = strtoupper($requestParameters['currency_code']);
+            } else if (!(array_key_exists('Action', $parameters) &&
+                        ($parameters['Action'] === 'SetOrderAttributes' || $parameters['Action'] === 'ConfirmOrderReference' || $parameters['Action'] === 'SetBillingAgreementDetails'))) {
+                // Only supply a default CurrencyCode parameter if not using SetOrderAttributes, ConfirmOrderReference, or SetBillingAgreementDetails
                 $parameters[$fieldMappings['currency_code']] = strtoupper($this->config['currency_code']);
             }
@@ -390,4 +443,48 @@
         return $parameters;
     }
+
+
+    /* setOrderItemCategories - helper function used by SetOrderAttributes API to set
+     * one or more Order Item Categories
+    */
+    private function setOrderItemCategories($parameters, $categories)
+    {
+        $categoryIndex = 0;
+        $categoryString = 'OrderAttributes.SellerOrderAttributes.OrderItemCategories.OrderItemCategory.';
+
+        foreach ($categories as $value) {
+            $categoryIndex = $categoryIndex + 1;
+            $parameters[$categoryString . $categoryIndex] = $value;
+        }
+
+        return $parameters;
+    }
+
+
+    /* setMerchantNotificationUrls - helper function used by SetMerchantNotificationConfiguration API to set
+     * one or more Notification Configurations
+    */
+    private function setNotificationConfigurationList($parameters, $configuration)
+    {
+        $configurationIndex = 0;
+        if (!is_array($configuration)) {
+            throw new \Exception('Notification Configuration List value ' . $configuration . ' is of type ' . gettype($configuration) . ' and should be an array value');
+        }
+        foreach ($configuration as $url => $events) {
+            $configurationIndex = $configurationIndex + 1;
+            $parameters['NotificationConfigurationList.NotificationConfiguration.' . $configurationIndex . '.NotificationUrl'] = $url;
+            $eventIndex = 0;
+            if (!is_array($events)) {
+                throw new \Exception('Notification Configuration Events value ' . $events . ' is of type ' . gettype($events) . ' and should be an array value');
+            }
+            foreach ($events as $event) {
+                $eventIndex = $eventIndex + 1;
+                $parameters['NotificationConfigurationList.NotificationConfiguration.' . $configurationIndex . '.EventTypes.EventTypeList.' . $eventIndex] = $event;
+            }
+        }
+
+        return $parameters;
+    }
+
 
     /* setProviderCreditDetails - sets the provider credit details sent via the Capture or Authorize API calls
@@ -396,9 +493,8 @@
      * @optional currency_code - [String]
      */
-
     private function setProviderCreditDetails($parameters, $providerCreditInfo)
     {
-	$providerIndex = 0;
-	$providerString = 'ProviderCreditList.member.';
+        $providerIndex = 0;
+        $providerString = 'ProviderCreditList.member.';
 
         $fieldMappings = array(
@@ -408,25 +504,23 @@
         );
 
-	foreach ($providerCreditInfo as $key => $value)
-	 {
-	    $value = array_change_key_case($value, CASE_LOWER);
-	    $providerIndex = $providerIndex + 1;
-
-	    foreach ($value as $param => $val)
-	    {
-		if (array_key_exists($param, $fieldMappings) && trim($val)!='') {
-		    $parameters[$providerString.$providerIndex. '.' .$fieldMappings[$param]] = $val;
-		}
-	    }
-
-	    // If currency code is not entered take it from the config array
-	    if(empty($parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']]))
-	    {
-		$parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']] = strtoupper($this->config['currency_code']);
-	    }
-	}
-
-	return $parameters;
-    }
+        foreach ($providerCreditInfo as $key => $value) {
+            $value = array_change_key_case($value, CASE_LOWER);
+            $providerIndex = $providerIndex + 1;
+
+            foreach ($value as $param => $val) {
+                if (array_key_exists($param, $fieldMappings) && trim($val)!='') {
+                    $parameters[$providerString.$providerIndex. '.' .$fieldMappings[$param]] = $val;
+                 }
+            }
+
+            // If currency code is not entered take it from the config array
+            if (empty($parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']])) {
+                $parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']] = strtoupper($this->config['currency_code']);
+            }
+        }
+
+        return $parameters;
+    }
+
 
     /* setProviderCreditReversalDetails - sets the reverse provider credit details sent via the Refund API call.
@@ -435,66 +529,170 @@
      * @optional currency_code - [String]
      */
-
     private function setProviderCreditReversalDetails($parameters, $providerCreditInfo)
     {
-	$providerIndex = 0;
-	$providerString = 'ProviderCreditReversalList.member.';
-
-        $fieldMappings = array(
-            'provider_id' 	   	=> 'ProviderId',
-            'credit_reversal_amount' 	=> 'CreditReversalAmount.Amount',
-            'currency_code' 		=> 'CreditReversalAmount.CurrencyCode'
-        );
-
-	foreach ($providerCreditInfo as $key => $value)
-	{
-	    $value = array_change_key_case($value, CASE_LOWER);
-	    $providerIndex = $providerIndex + 1;
-
-	    foreach ($value as $param => $val)
-	    {
-		if (array_key_exists($param, $fieldMappings) && trim($val)!='') {
-		    $parameters[$providerString.$providerIndex. '.' .$fieldMappings[$param]] = $val;
-		}
-	    }
-
-	    // If currency code is not entered take it from the config array
-	    if(empty($parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']]))
-	    {
-		$parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']] = strtoupper($this->config['currency_code']);
-	    }
-	}
-
-	return $parameters;
+        $providerIndex = 0;
+        $providerString = 'ProviderCreditReversalList.member.';
+
+        $fieldMappings = array(
+            'provider_id'            => 'ProviderId',
+            'credit_reversal_amount' => 'CreditReversalAmount.Amount',
+            'currency_code'          => 'CreditReversalAmount.CurrencyCode'
+        );
+
+        foreach ($providerCreditInfo as $key => $value) {
+            $value = array_change_key_case($value, CASE_LOWER);
+            $providerIndex = $providerIndex + 1;
+
+            foreach ($value as $param => $val) {
+                if (array_key_exists($param, $fieldMappings) && trim($val)!='') {
+                    $parameters[$providerString.$providerIndex. '.' .$fieldMappings[$param]] = $val;
+                 }
+            }
+
+            // If currency code is not entered take it from the config array
+            if (empty($parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']])) {
+                $parameters[$providerString.$providerIndex. '.' .$fieldMappings['currency_code']] = strtoupper($this->config['currency_code']);
+            }
+        }
+
+        return $parameters;
+    }
+
+    /* GetMerchantAccountStatus API call - Returns the status of the Merchant Account.
+     * @see TODO
+
+     * @param requestParameters['merchant_id'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function getMerchantAccountStatus($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'GetMerchantAccountStatus';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'         => 'SellerId',
+            'mws_auth_token'      => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
     }
 
     /* GetOrderReferenceDetails API call - Returns details about the Order Reference object and its current state.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetOrderReferenceDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751970
      *
      * @param requestParameters['merchant_id'] - [String]
      * @param requestParameters['amazon_order_reference_id'] - [String]
      * @optional requestParameters['address_consent_token'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
+     * @optional requestParameters['access_token'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     *
+     * You cannot pass both address_consent_token and access_token in
+     * the same call or you will encounter a 400/"AmbiguousToken" error
+     */
     public function getOrderReferenceDetails($requestParameters = array())
     {
 
+        $parameters           = array();
         $parameters['Action'] = 'GetOrderReferenceDetails';
         $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'               => 'SellerId',
             'amazon_order_reference_id' => 'AmazonOrderReferenceId',
-            'address_consent_token' 	=> 'AddressConsentToken',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-        return ($responseObject);
-    }
+            'address_consent_token'     => 'AddressConsentToken',
+            'access_token'              => 'AccessToken',
+            'mws_auth_token'            => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
+
+    /* ListOrderReference API call - Returns details about the Order Reference object and its current state from the sellers.
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751970
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['query_id'] - [String]
+     * @param requestParameters['query_id_type'] - [String] (SellerOrderId)
+     * @optional requestParameters['page_size'] - [Int]
+     * @optional requestParameters['created_start_time'] - [String] (Date/Time ISO8601)
+     * @optional requestParameters['created_end_time'] - [String] (Date/Time ISO8601) Limited to 31 days
+     * @optional requestParameters['sort_order'] - [String] (Ascending/Descending)
+     * @optional requestParameters['mws_auth_token'] - [String]
+     * @optional requestParameters['status_list'] - [Array]
+     */
+    public function listOrderReference($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'ListOrderReference';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $payment_domains = array(
+            "us"    => "NA_USD",
+            "jp"    => "FE_JPY",
+            "de"    => "EU_EUR",
+            "uk"    => "EU_GBP"
+        );
+
+        $requestParameters['payment_domain'] = $payment_domains[strtolower($this->config['region'])];
+
+        $fieldMappings = array(
+            'merchant_id'        => 'SellerId',
+            'mws_auth_token'     => 'MWSAuthToken',
+            
+            'query_id'           => 'QueryId',
+            'query_id_type'      => 'QueryIdType',
+            'page_size'          => 'PageSize',
+            'created_start_time' => 'CreatedTimeRange.StartTime',
+            'created_end_time'   => 'CreatedTimeRange.EndTime',
+            'sort_order'         => 'SortOrder',
+            'payment_domain'     => 'PaymentDomain'
+        );
+
+        if( $requestParameters['order_status_list'] ){
+            $status_index = 0;
+            foreach ($requestParameters['order_status_list'] as $status) {
+                $status_index++;
+                $requestParameters['order_status_list_'.$status_index] = $status;
+                $fieldMappings['order_status_list_'.$status_index] = 'OrderReferenceStatusListFilter.OrderReferenceStatus.'.$status_index;
+            }
+        }
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
+    /* ListOrderReferenceByNextToken API call - Returns details about the Order Reference object and its current
+     * state from the sellers.
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751970
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['next_token'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function listOrderReferenceByNextToken($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'ListOrderReferenceByNextToken';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'    => 'SellerId',
+            'mws_auth_token' => 'MWSAuthToken',
+            
+            'next_page_token' => 'NextPageToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* SetOrderReferenceDetails API call - Sets order reference details such as the order total and a description for the order.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_SetOrderReferenceDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751960
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -507,7 +705,8 @@
      * @optional requestParameters['store_name'] - [String]
      * @optional requestParameters['custom_information'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
+     * @optional requestParameters['supplementary_data'] - [String]
+     * @optional requestParameters['request_payment_authorization'] - [Boolean]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
     public function setOrderReferenceDetails($requestParameters = array())
     {
@@ -517,48 +716,109 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'                   => 'SellerId',
+            'amazon_order_reference_id'     => 'AmazonOrderReferenceId',
+            'amount'                        => 'OrderReferenceAttributes.OrderTotal.Amount',
+            'currency_code'                 => 'OrderReferenceAttributes.OrderTotal.CurrencyCode',
+            'platform_id'                   => 'OrderReferenceAttributes.PlatformId',
+            'seller_note'                   => 'OrderReferenceAttributes.SellerNote',
+            'seller_order_id'               => 'OrderReferenceAttributes.SellerOrderAttributes.SellerOrderId',
+            'store_name'                    => 'OrderReferenceAttributes.SellerOrderAttributes.StoreName',
+            'custom_information'            => 'OrderReferenceAttributes.SellerOrderAttributes.CustomInformation',
+            'supplementary_data'            => 'OrderReferenceAttributes.SellerOrderAttributes.SupplementaryData',
+            'request_payment_authorization' => 'OrderReferenceAttributes.RequestPaymentAuthorization',
+            'mws_auth_token'                => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
+
+    /* SetOrderAttributes API call - Sets order reference details such as the order total and a description for the order.
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['amazon_order_reference_id'] - [String]
+     * @optional requestParameters['amount'] - [String]
+     * @optional requestParameters['currency_code'] - [String]
+     * @optional requestParameters['platform_id'] - [String]
+     * @optional requestParameters['seller_note'] - [String]
+     * @optional requestParameters['seller_order_id'] - [String]
+     * @optional requestParameters['store_name'] - [String]
+     * @optional requestParameters['custom_information'] - [String]
+     * @optional requestParameters['supplementary_data'] - [String]
+     * @optional requestParameters['request_payment_authorization'] - [Boolean]
+     * @optional requestParameters['payment_service_provider_id'] - [String]
+     * @optional requestParameters['payment_service_provider_order_id'] - [String]
+     * @optional requestParameters['order_item_categories'] - [array()]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function setOrderAttributes($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'SetOrderAttributes';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'                       => 'SellerId',
+            'amazon_order_reference_id'         => 'AmazonOrderReferenceId',
+            'amount'                            => 'OrderAttributes.OrderTotal.Amount',
+            'currency_code'                     => 'OrderAttributes.OrderTotal.CurrencyCode',
+            'platform_id'                       => 'OrderAttributes.PlatformId',
+            'seller_note'                       => 'OrderAttributes.SellerNote',
+            'seller_order_id'                   => 'OrderAttributes.SellerOrderAttributes.SellerOrderId',
+            'store_name'                        => 'OrderAttributes.SellerOrderAttributes.StoreName',
+            'custom_information'                => 'OrderAttributes.SellerOrderAttributes.CustomInformation',
+            'supplementary_data'                => 'OrderAttributes.SellerOrderAttributes.SupplementaryData',
+            'request_payment_authorization'     => 'OrderAttributes.RequestPaymentAuthorization',
+            'payment_service_provider_id'       => 'OrderAttributes.PaymentServiceProviderAttributes.PaymentServiceProviderId',
+            'payment_service_provider_order_id' => 'OrderAttributes.PaymentServiceProviderAttributes.PaymentServiceProviderOrderId',
+            'order_item_categories'             => array(),
+            'mws_auth_token'                    => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
+
+    /* ConfirmOrderReference API call - Confirms that the order reference is free of constraints and all required information has been set on the order reference.
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751980
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['amazon_order_reference_id'] - [String]
+     * @optional requestParameters['success_url'] - [String]
+     * @optional requestParameters['failure_url'] - [String]
+     * @optional requestParameters['authorization_amount'] - [String]
+     * @optional requestParameters['currency_code'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function confirmOrderReference($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'ConfirmOrderReference';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'               => 'SellerId',
             'amazon_order_reference_id' => 'AmazonOrderReferenceId',
-            'amount' 			=> 'OrderReferenceAttributes.OrderTotal.Amount',
-            'currency_code' 		=> 'OrderReferenceAttributes.OrderTotal.CurrencyCode',
-            'platform_id' 		=> 'OrderReferenceAttributes.PlatformId',
-            'seller_note' 		=> 'OrderReferenceAttributes.SellerNote',
-            'seller_order_id' 		=> 'OrderReferenceAttributes.SellerOrderAttributes.SellerOrderId',
-            'store_name' 		=> 'OrderReferenceAttributes.SellerOrderAttributes.StoreName',
-            'custom_information'	=> 'OrderReferenceAttributes.SellerOrderAttributes.CustomInformation',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-	return ($responseObject);
-    }
-
-    /* ConfirmOrderReferenceDetails API call - Confirms that the order reference is free of constraints and all required information has been set on the order reference.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_ConfirmOrderReference.html
-
-     * @param requestParameters['merchant_id'] - [String]
-     * @param requestParameters['amazon_order_reference_id'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
-    public function confirmOrderReference($requestParameters = array())
-    {
-        $parameters           = array();
-        $parameters['Action'] = 'ConfirmOrderReference';
-        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
-
-        $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
-            'amazon_order_reference_id' => 'AmazonOrderReferenceId',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
-
-    /* CancelOrderReferenceDetails API call - Cancels a previously confirmed order reference.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_CancelOrderReference.html
+            'success_url'               => 'SuccessUrl',
+            'failure_url'               => 'FailureUrl',
+            'authorization_amount'      => 'AuthorizationAmount.Amount',
+            'currency_code'             => 'AuthorizationAmount.CurrencyCode',
+            'mws_auth_token'            => 'MWSAuthToken'
+        );
+
+        if (isset($requestParameters['authorization_amount']) && !isset($requestParameters['currency_code'])) {
+            $requestParameters['currency_code'] = strtoupper($this->config['currency_code']);
+        }
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
+
+    /* CancelOrderReference API call - Cancels a previously confirmed order reference.
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751990
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -567,5 +827,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function cancelOrderReference($requestParameters = array())
     {
@@ -575,18 +834,19 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'               => 'SellerId',
             'amazon_order_reference_id' => 'AmazonOrderReferenceId',
-            'cancelation_reason' 	=> 'CancelationReason',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-	return ($responseObject);
-    }
-
-    /* CloseOrderReferenceDetails API call - Confirms that an order reference has been fulfilled (fully or partially)
+            'cancelation_reason'        => 'CancelationReason',
+            'mws_auth_token'            => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
+
+    /* CloseOrderReference API call - Confirms that an order reference has been fulfilled (fully or partially)
      * and that you do not expect to create any new authorizations on this order reference.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_CloseOrderReference.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752000
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -595,5 +855,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function closeOrderReference($requestParameters = array())
     {
@@ -603,17 +862,18 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'               => 'SellerId',
             'amazon_order_reference_id' => 'AmazonOrderReferenceId',
-            'closure_reason' 		=> 'ClosureReason',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'closure_reason'            => 'ClosureReason',
+            'mws_auth_token'            => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
 
     /* CloseAuthorization API call - Closes an authorization.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_CloseOrderReference.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752070
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -622,5 +882,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function closeAuthorization($requestParameters = array())
     {
@@ -630,8 +889,8 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
-            'amazon_authorization_id' 	=> 'AmazonAuthorizationId',
-            'closure_reason' 		=> 'ClosureReason',
-            'mws_auth_token' 		=> 'MWSAuthToken'
+            'merchant_id'         => 'SellerId',
+            'amazon_authorization_id'     => 'AmazonAuthorizationId',
+            'closure_reason'         => 'ClosureReason',
+            'mws_auth_token'         => 'MWSAuthToken'
         );
 
@@ -642,5 +901,5 @@
 
     /* Authorize API call - Reserves a specified amount against the payment method(s) stored in the order reference.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_Authorize.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752010
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -649,5 +908,5 @@
      * @param requestParameters['currency_code'] - [String]
      * @param requestParameters['authorization_reference_id'] [String]
-     * @optional requestParameters['capture_now'] [String]
+     * @optional requestParameters['capture_now'] [Boolean]
      * @optional requestParameters['provider_credit_details'] - [array (array())]
      * @optional requestParameters['seller_authorization_note'] [String]
@@ -657,4 +916,5 @@
      */
 
+
     public function authorize($requestParameters = array())
     {
@@ -664,24 +924,25 @@
 
         $fieldMappings = array(
-            'merchant_id' 		 => 'SellerId',
+            'merchant_id'                => 'SellerId',
             'amazon_order_reference_id'  => 'AmazonOrderReferenceId',
-            'authorization_amount' 	 => 'AuthorizationAmount.Amount',
-            'currency_code' 		 => 'AuthorizationAmount.CurrencyCode',
+            'authorization_amount'       => 'AuthorizationAmount.Amount',
+            'currency_code'              => 'AuthorizationAmount.CurrencyCode',
             'authorization_reference_id' => 'AuthorizationReferenceId',
-            'capture_now' 		 => 'CaptureNow',
-	    'provider_credit_details'	 => array(),
+            'capture_now'                => 'CaptureNow',
+            'provider_credit_details'    => array(),
             'seller_authorization_note'  => 'SellerAuthorizationNote',
-            'transaction_timeout' 	 => 'TransactionTimeout',
-            'soft_descriptor' 		 => 'SoftDescriptor',
-            'mws_auth_token' 		 => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'transaction_timeout'        => 'TransactionTimeout',
+            'soft_descriptor'            => 'SoftDescriptor',
+            'mws_auth_token'             => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
 
     /* GetAuthorizationDetails API call - Returns the status of a particular authorization and the total amount captured on the authorization.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetAuthorizationDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752030
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -689,5 +950,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getAuthorizationDetails($requestParameters = array())
     {
@@ -697,16 +957,15 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
-            'amazon_authorization_id' 	=> 'AmazonAuthorizationId',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
+            'merchant_id'             => 'SellerId',
+            'amazon_authorization_id' => 'AmazonAuthorizationId',
+            'mws_auth_token'          => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
         return ($responseObject);
     }
 
     /* Capture API call - Captures funds from an authorized payment instrument.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_Capture.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752040
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -720,5 +979,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function capture($requestParameters = array())
     {
@@ -728,22 +986,22 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
-            'amazon_authorization_id' 	=> 'AmazonAuthorizationId',
-            'capture_amount' 		=> 'CaptureAmount.Amount',
-            'currency_code' 		=> 'CaptureAmount.CurrencyCode',
-            'capture_reference_id' 	=> 'CaptureReferenceId',
-	    'provider_credit_details'	=> array(),
-            'seller_capture_note' 	=> 'SellerCaptureNote',
-            'soft_descriptor' 		=> 'SoftDescriptor',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-	return ($responseObject);
-    }
+            'merchant_id'             => 'SellerId',
+            'amazon_authorization_id' => 'AmazonAuthorizationId',
+            'capture_amount'          => 'CaptureAmount.Amount',
+            'currency_code'           => 'CaptureAmount.CurrencyCode',
+            'capture_reference_id'    => 'CaptureReferenceId',
+            'provider_credit_details' => array(),
+            'seller_capture_note'     => 'SellerCaptureNote',
+            'soft_descriptor'         => 'SoftDescriptor',
+            'mws_auth_token'          => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* GetCaptureDetails API call - Returns the status of a particular capture and the total amount refunded on the capture.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetCaptureDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752060
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -751,5 +1009,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getCaptureDetails($requestParameters = array())
     {
@@ -759,16 +1016,16 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'       => 'SellerId',
             'amazon_capture_id' => 'AmazonCaptureId',
-            'mws_auth_token' 	=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'mws_auth_token'    => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* Refund API call - Refunds a previously captured amount.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_Refund.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752080
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -782,5 +1039,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function refund($requestParameters = array())
     {
@@ -790,22 +1046,22 @@
 
         $fieldMappings = array(
-            'merchant_id' 	  					=> 'SellerId',
-            'amazon_capture_id'   				=> 'AmazonCaptureId',
-            'refund_reference_id' 				=> 'RefundReferenceId',
-            'refund_amount' 	  				=> 'RefundAmount.Amount',
-            'currency_code' 	  				=> 'RefundAmount.CurrencyCode',
-			'provider_credit_reversal_details'	=> array(),
-            'seller_refund_note'  				=> 'SellerRefundNote',
-            'soft_descriptor' 	  				=> 'SoftDescriptor',
-            'mws_auth_token' 	  				=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'merchant_id'                      => 'SellerId',
+            'amazon_capture_id'                => 'AmazonCaptureId',
+            'refund_reference_id'              => 'RefundReferenceId',
+            'refund_amount'                    => 'RefundAmount.Amount',
+            'currency_code'                    => 'RefundAmount.CurrencyCode',
+            'provider_credit_reversal_details' => array(),
+            'seller_refund_note'               => 'SellerRefundNote',
+            'soft_descriptor'                  => 'SoftDescriptor',
+            'mws_auth_token'                   => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* GetRefundDetails API call - Returns the status of a particular refund.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetRefundDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752100
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -813,5 +1069,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getRefundDetails($requestParameters = array())
     {
@@ -821,18 +1076,19 @@
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'         => 'SellerId',
             'amazon_refund_id'  => 'AmazonRefundId',
-            'mws_auth_token' 	=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
-
-    /* GetServiceStatus API Call - Returns the operational status of the Off-Amazon Payments API section
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetServiceStatus.html
-     *
-     * The GetServiceStatus operation returns the operational status of the Off-Amazon Payments API
+            'mws_auth_token'     => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+
+        return ($responseObject);
+    }
+
+
+    /* GetServiceStatus API Call - Returns the operational status of the OffAmazonPayments API section
+     * @see https://pay.amazon.com/developer/documentation/apireference/201752110
+     *
+     * The GetServiceStatus operation returns the operational status of the OffAmazonPayments API
      * section of Amazon Marketplace Web Service (Amazon MWS).
      * Status values are GREEN, GREEN_I, YELLOW, and RED.
@@ -841,5 +1097,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getServiceStatus($requestParameters = array())
     {
@@ -855,14 +1110,15 @@
         $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
 
-	return ($responseObject);
-    }
+        return ($responseObject);
+    }
+
 
     /* CreateOrderReferenceForId API Call - Creates an order reference for the given object
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_CreateOrderReferenceForId.html
-     *
-     * @param requestParameters['merchant_id'] - [String]
-     * @param requestParameters['Id'] - [String]
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751670
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['id'] - [String]
      * @optional requestParameters['inherit_shipping_address'] [Boolean]
-     * @optional requestParameters['ConfirmNow'] - [Boolean]
+     * @optional requestParameters['confirm_now'] - [Boolean]
      * @optional Amount (required when confirm_now is set to true) [String]
      * @optional requestParameters['currency_code'] - [String]
@@ -870,8 +1126,8 @@
      * @optional requestParameters['seller_order_id'] - [String]
      * @optional requestParameters['store_name'] - [String]
+     * @optional requestParameters['supplementary_data'] - [String]
      * @optional requestParameters['custom_information'] - [String]
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function createOrderReferenceForId($requestParameters = array())
     {
@@ -881,32 +1137,37 @@
 
         $fieldMappings = array(
-            'merchant_id' 				=> 'SellerId',
-            'id' 						=> 'Id',
-            'id_type' 					=> 'IdType',
-            'inherit_shipping_address' 	=> 'InheritShippingAddress',
-            'confirm_now' 				=> 'ConfirmNow',
-            'amount' 					=> 'OrderReferenceAttributes.OrderTotal.Amount',
-            'currency_code' 			=> 'OrderReferenceAttributes.OrderTotal.CurrencyCode',
-            'platform_id' 				=> 'OrderReferenceAttributes.PlatformId',
-            'seller_note' 				=> 'OrderReferenceAttributes.SellerNote',
-            'seller_order_id' 			=> 'OrderReferenceAttributes.SellerOrderAttributes.SellerOrderId',
-            'store_name' 				=> 'OrderReferenceAttributes.SellerOrderAttributes.StoreName',
-            'custom_information' 		=> 'OrderReferenceAttributes.SellerOrderAttributes.CustomInformation',
-            'mws_auth_token' 			=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'merchant_id'              => 'SellerId',
+            'id'                       => 'Id',
+            'id_type'                  => 'IdType',
+            'inherit_shipping_address' => 'InheritShippingAddress',
+            'confirm_now'              => 'ConfirmNow',
+            'amount'                   => 'OrderReferenceAttributes.OrderTotal.Amount',
+            'currency_code'            => 'OrderReferenceAttributes.OrderTotal.CurrencyCode',
+            'platform_id'              => 'OrderReferenceAttributes.PlatformId',
+            'seller_note'              => 'OrderReferenceAttributes.SellerNote',
+            'seller_order_id'          => 'OrderReferenceAttributes.SellerOrderAttributes.SellerOrderId',
+            'store_name'               => 'OrderReferenceAttributes.SellerOrderAttributes.StoreName',
+            'supplementary_data'       => 'OrderReferenceAttributes.SupplementaryData',
+            'custom_information'       => 'OrderReferenceAttributes.SellerOrderAttributes.CustomInformation',
+            'mws_auth_token'           => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* GetBillingAgreementDetails API Call - Returns details about the Billing Agreement object and its current state.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_GetBillingAgreementDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751690
      *
      * @param requestParameters['merchant_id'] - [String]
      * @param requestParameters['amazon_billing_agreement_id'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
+     * @optional requestParameters['address_consent_token'] - [String]
+     * @optional requestParameters['access_token'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     *
+     * You cannot pass both address_consent_token and access_token in
+     * the same call or you will encounter a 400/"AmbiguousToken" error
+     */
     public function getBillingAgreementDetails($requestParameters = array())
     {
@@ -916,17 +1177,18 @@
 
         $fieldMappings = array(
-            'merchant_id' 		  			=> 'SellerId',
-            'amazon_billing_agreement_id' 	=> 'AmazonBillingAgreementId',
-            'address_consent_token' 	  	=> 'AddressConsentToken',
-            'mws_auth_token' 		  		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-	return ($responseObject);
-    }
+            'merchant_id'                 => 'SellerId',
+            'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
+            'address_consent_token'       => 'AddressConsentToken',
+            'access_token'                => 'AccessToken',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* SetBillingAgreementDetails API call - Sets Billing Agreement details such as a description of the agreement and other information about the seller.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_SetBillingAgreementDetails.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751700
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -939,7 +1201,9 @@
      * @optional requestParameters['store_name'] - [String]
      * @optional requestParameters['custom_information'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
+     * @optional requestParameters['billing_agreement_type'] - [String] either 'CustomerInitiatedTransaction' or 'MerchantInitiatedTransaction'
+     * @optional requestParameters['subscription_amount'] - [String]
+     * @optional requestParameters['currency_code'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
     public function setBillingAgreementDetails($requestParameters = array())
     {
@@ -949,27 +1213,35 @@
 
         $fieldMappings = array(
-            'merchant_id' 		  => 'SellerId',
+            'merchant_id'                 => 'SellerId',
             'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
-            'platform_id' 		  => 'BillingAgreementAttributes.PlatformId',
-            'seller_note' 		  => 'BillingAgreementAttributes.SellerNote',
+            'platform_id'                 => 'BillingAgreementAttributes.PlatformId',
+            'seller_note'                 => 'BillingAgreementAttributes.SellerNote',
             'seller_billing_agreement_id' => 'BillingAgreementAttributes.SellerBillingAgreementAttributes.SellerBillingAgreementId',
-            'custom_information' 	  => 'BillingAgreementAttributes.SellerBillingAgreementAttributes.CustomInformation',
-            'store_name' 		  => 'BillingAgreementAttributes.SellerBillingAgreementAttributes.StoreName',
-            'mws_auth_token' 		  => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'custom_information'          => 'BillingAgreementAttributes.SellerBillingAgreementAttributes.CustomInformation',
+            'store_name'                  => 'BillingAgreementAttributes.SellerBillingAgreementAttributes.StoreName',
+            'billing_agreement_type'      => 'BillingAgreementAttributes.BillingAgreementType',
+            'subscription_amount'         => 'BillingAgreementAttributes.SubscriptionAmount.Amount',
+            'currency_code'               => 'BillingAgreementAttributes.SubscriptionAmount.CurrencyCode',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        if (isset($requestParameters['subscription_amount']) && !isset($requestParameters['currency_code'])) {
+            $requestParameters['currency_code'] = strtoupper($this->config['currency_code']);
+        }
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* ConfirmBillingAgreement API Call - Confirms that the Billing Agreement is free of constraints and all required information has been set on the Billing Agreement.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_ConfirmBillingAgreement.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751710
      *
      * @param requestParameters['merchant_id'] - [String]
      * @param requestParameters['amazon_billing_agreement_id'] - [String]
-     * @optional requestParameters['mws_auth_token'] - [String]
-     */
-
+     * @optional requestParameters['success_url'] - [String]
+     * @optional requestParameters['failure_url'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
     public function confirmBillingAgreement($requestParameters = array())
     {
@@ -979,16 +1251,18 @@
 
         $fieldMappings = array(
-            'merchant_id' 		  => 'SellerId',
+            'merchant_id'                 => 'SellerId',
             'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
-            'mws_auth_token' 		  => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'success_url'                 => 'SuccessUrl',
+            'failure_url'                 => 'FailureUrl',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* ValidateBillignAgreement API Call - Validates the status of the Billing Agreement object and the payment method associated with it.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_ValidateBillingAgreement.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751720
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -996,5 +1270,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function validateBillingAgreement($requestParameters = array())
     {
@@ -1004,25 +1277,25 @@
 
         $fieldMappings = array(
-            'merchant_id' 		  => 'SellerId',
+            'merchant_id'                 => 'SellerId',
             'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
-            'mws_auth_token' 		  => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* AuthorizeOnBillingAgreement API call - Reserves a specified amount against the payment method(s) stored in the Billing Agreement.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_AuthorizeOnBillingAgreement.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751940
      *
      * @param requestParameters['merchant_id'] - [String]
      * @param requestParameters['amazon_billing_agreement_id'] - [String]
-     * @param requestParameters['authorization_reference_id'] [String]
-     * @param requestParameters['authorization_amount'] [String]
+     * @param requestParameters['authorization_reference_id'] - [String]
+     * @param requestParameters['authorization_amount'] - [String]
      * @param requestParameters['currency_code'] - [String]
      * @optional requestParameters['seller_authorization_note'] [String]
      * @optional requestParameters['transaction_timeout'] - Defaults to 1440 minutes
-     * @optional requestParameters['capture_now'] [String]
+     * @optional requestParameters['capture_now'] [Boolean]
      * @optional requestParameters['soft_descriptor'] - - [String]
      * @optional requestParameters['seller_note'] - [String]
@@ -1031,8 +1304,8 @@
      * @optional requestParameters['seller_order_id'] - [String]
      * @optional requestParameters['store_name'] - [String]
+     * @optional requestParameters['supplementary_data'] - [String]
      * @optional requestParameters['inherit_shipping_address'] [Boolean] - Defaults to true
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function authorizeOnBillingAgreement($requestParameters = array())
     {
@@ -1042,29 +1315,30 @@
 
         $fieldMappings = array(
-            'merchant_id' 			=> 'SellerId',
-            'amazon_billing_agreement_id' 	=> 'AmazonBillingAgreementId',
-            'authorization_reference_id' 	=> 'AuthorizationReferenceId',
-            'authorization_amount' 		=> 'AuthorizationAmount.Amount',
-            'currency_code' 			=> 'AuthorizationAmount.CurrencyCode',
-            'seller_authorization_note' 	=> 'SellerAuthorizationNote',
-            'transaction_timeout' 		=> 'TransactionTimeout',
-            'capture_now' 			=> 'CaptureNow',
-            'soft_descriptor' 			=> 'SoftDescriptor',
-            'seller_note' 			=> 'SellerNote',
-            'platform_id' 			=> 'PlatformId',
-            'custom_information' 		=> 'SellerOrderAttributes.CustomInformation',
-            'seller_order_id' 			=> 'SellerOrderAttributes.SellerOrderId',
-            'store_name' 			=> 'SellerOrderAttributes.StoreName',
-            'inherit_shipping_address' 		=> 'InheritShippingAddress',
-            'mws_auth_token' 			=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-	return ($responseObject);
-    }
+            'merchant_id'                 => 'SellerId',
+            'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
+            'authorization_reference_id'  => 'AuthorizationReferenceId',
+            'authorization_amount'        => 'AuthorizationAmount.Amount',
+            'currency_code'               => 'AuthorizationAmount.CurrencyCode',
+            'seller_authorization_note'   => 'SellerAuthorizationNote',
+            'transaction_timeout'         => 'TransactionTimeout',
+            'capture_now'                 => 'CaptureNow',
+            'soft_descriptor'             => 'SoftDescriptor',
+            'seller_note'                 => 'SellerNote',
+            'platform_id'                 => 'PlatformId',
+            'custom_information'          => 'SellerOrderAttributes.CustomInformation',
+            'seller_order_id'             => 'SellerOrderAttributes.SellerOrderId',
+            'store_name'                  => 'SellerOrderAttributes.StoreName',
+            'supplementary_data'          => 'SellerOrderAttributes.SupplementaryData',
+            'inherit_shipping_address'    => 'InheritShippingAddress',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* CloseBillingAgreement API Call - Returns details about the Billing Agreement object and its current state.
-     * @see http://docs.developer.amazonservices.com/en_US/off_amazon_payments/OffAmazonPayments_CloseBillingAgreement.html
+     * @see https://pay.amazon.com/developer/documentation/apireference/201751950
      *
      * @param requestParameters['merchant_id'] - [String]
@@ -1073,5 +1347,4 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function closeBillingAgreement($requestParameters = array())
     {
@@ -1081,14 +1354,58 @@
 
         $fieldMappings = array(
-            'merchant_id' 		  => 'SellerId',
+            'merchant_id'                 => 'SellerId',
             'amazon_billing_agreement_id' => 'AmazonBillingAgreementId',
-            'closure_reason' 		  => 'ClosureReason',
-            'mws_auth_token' 		  => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'closure_reason'              => 'ClosureReason',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
+
+    /* GetMerchantNotificationConfiguration API Call - Returns details about the defined IPN endpoints
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function getMerchantNotificationConfiguration($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'GetMerchantNotificationConfiguration';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'                 => 'SellerId',
+            'mws_auth_token'              => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
+
+    /* SetMerchantNotificationConfiguration API Call - Set IPN endpoints
+     *
+     * @param requestParameters['merchant_id'] - [String]
+     * @param requestParameters['notification_configuration_list'] - [Array]
+     * @optional requestParameters['mws_auth_token'] - [String]
+     */
+    public function setMerchantNotificationConfiguration($requestParameters = array())
+    {
+        $parameters           = array();
+        $parameters['Action'] = 'SetMerchantNotificationConfiguration';
+        $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
+
+        $fieldMappings = array(
+            'merchant_id'                     => 'SellerId',
+            'notification_configuration_list' => array(),
+            'mws_auth_token'                  => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* charge convenience method
@@ -1114,22 +1431,19 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function charge($requestParameters = array()) {
 
-	$requestParameters = array_change_key_case($requestParameters, CASE_LOWER);
-	$requestParameters= $this->trimArray($requestParameters);
-
-	$setParameters = $authorizeParameters = $confirmParameters = $requestParameters;
+        $requestParameters = array_change_key_case($requestParameters, CASE_LOWER);
+        $requestParameters = $this->trimArray($requestParameters);
+
+        $setParameters = $authorizeParameters = $confirmParameters = $requestParameters;
 
         $chargeType = '';
-	
-	if (!empty($requestParameters['amazon_order_reference_id']))
-	{
-	    $chargeType = 'OrderReference';
-	    
-	} elseif(!empty($requestParameters['amazon_billing_agreement_id'])) {
-	    $chargeType = 'BillingAgreement';
-	    
-	} elseif (!empty($requestParameters['amazon_reference_id'])) {
+    
+        if (!empty($requestParameters['amazon_order_reference_id'])) {
+            $chargeType = 'OrderReference';
+        } elseif (!empty($requestParameters['amazon_billing_agreement_id'])) {
+            $chargeType = 'BillingAgreement';
+        
+        } elseif (!empty($requestParameters['amazon_reference_id'])) {
             switch (substr(strtoupper($requestParameters['amazon_reference_id']), 0, 1)) {
                 case 'P':
@@ -1154,5 +1468,5 @@
         }
 
-	// Set the other parameters if the values are present
+        // Set the other parameters if the values are present
         $setParameters['amount'] = !empty($requestParameters['charge_amount']) ? $requestParameters['charge_amount'] : '';
         $authorizeParameters['authorization_amount'] = !empty($requestParameters['charge_amount']) ? $requestParameters['charge_amount'] : '';
@@ -1168,57 +1482,58 @@
         $authorizeParameters['capture_now'] = !empty($requestParameters['capture_now']) ? $requestParameters['capture_now'] : false;
 
-	$response = $this->makeChargeCalls($chargeType, $setParameters, $confirmParameters, $authorizeParameters);
-	return $response;
-    }
+        $response = $this->makeChargeCalls($chargeType, $setParameters, $confirmParameters, $authorizeParameters);
+        return $response;
+    }
+
 
     /* makeChargeCalls - makes API calls based off the charge type (OrderReference or BillingAgreement) */
-
     private function makeChargeCalls($chargeType, $setParameters, $confirmParameters, $authorizeParameters)
     {
-	switch ($chargeType) {
+        switch ($chargeType) {
             
-	    case 'OrderReference':
-		
-		// Get the Order Reference details and feed the response object to the ResponseParser
+            case 'OrderReference':
+        
+                // Get the Order Reference details and feed the response object to the ResponseParser
                 $responseObj = $this->getOrderReferenceDetails($setParameters);
-		
-		// Call the function getOrderReferenceDetailsStatus in ResponseParser.php providing it the XML response
-                // $oroStatus is an array containing the State of the Order Reference ID
+        
+               // Call the function getOrderReferenceDetailsStatus in ResponseParser.php providing it the XML response
+               // $oroStatus is an array containing the State of the Order Reference ID
+               $oroStatus = $responseObj->getOrderReferenceDetailsStatus($responseObj->toXml());
+        
+                if ($oroStatus['State'] === 'Draft') {
+                    $response = $this->setOrderReferenceDetails($setParameters);
+                    if ($this->success) {
+                        $this->confirmOrderReference($confirmParameters);
+                    }
+                }
+        
+                $responseObj = $this->getOrderReferenceDetails($setParameters);
+        
+                // Check the Order Reference Status again before making the Authorization.
                 $oroStatus = $responseObj->getOrderReferenceDetailsStatus($responseObj->toXml());
-		
-		if ($oroStatus['State'] === 'Draft') {
-		    $response = $this->setOrderReferenceDetails($setParameters);
-		    if ($this->success) {
-                    $this->confirmOrderReference($confirmParameters);
-		    }
-		}
-		
-                $responseObj = $this->getOrderReferenceDetails($setParameters);
-		
-		// Check the Order Reference Status again before making the Authorization.
-                $oroStatus = $responseObj->getOrderReferenceDetailsStatus($responseObj->toXml());
-		
-		if ($oroStatus['State'] === 'Open') {
-		    if ($this->success) {
-                    $response = $this->Authorize($authorizeParameters);
-		    }
-		}
-		if ($oroStatus['State'] != 'Open' && $oroStatus['State'] != 'Draft') {
-		    throw new \Exception('The Order Reference is in the ' . $oroStatus['State'] . " State. It should be in the Draft or Open State");
-		}
+        
+                if ($oroStatus['State'] === 'Open') {
+                    if ($this->success) {
+                        $response = $this->authorize($authorizeParameters);
+                    }
+                }
+
+                if ($oroStatus['State'] != 'Open' && $oroStatus['State'] != 'Draft') {
+                    throw new \Exception('The Order Reference is in the ' . $oroStatus['State'] . " State. It should be in the Draft or Open State");
+                }
                 
-		return $response;
+                return $response;
             
-	    case 'BillingAgreement':
+            case 'BillingAgreement':
                 
-		// Get the Billing Agreement details and feed the response object to the ResponseParser
+                // Get the Billing Agreement details and feed the response object to the ResponseParser
                 
-		$responseObj = $this->getBillingAgreementDetails($setParameters);
+                $responseObj = $this->getBillingAgreementDetails($setParameters);
                 
-		// Call the function getBillingAgreementDetailsStatus in ResponseParser.php providing it the XML response
+                // Call the function getBillingAgreementDetailsStatus in ResponseParser.php providing it the XML response
                 // $baStatus is an array containing the State of the Billing Agreement
                 $baStatus = $responseObj->getBillingAgreementDetailsStatus($responseObj->toXml());
                 
-		if ($baStatus['State'] === 'Draft') {
+                if ($baStatus['State'] === 'Draft') {
                     $response = $this->setBillingAgreementDetails($setParameters);
                     if ($this->success) {
@@ -1227,19 +1542,23 @@
                 }
                 
-		// Check the Billing Agreement status again before making the Authorization.
+                // Check the Billing Agreement status again before making the Authorization.
                 $responseObj = $this->getBillingAgreementDetails($setParameters);
                 $baStatus = $responseObj->getBillingAgreementDetailsStatus($responseObj->toXml());
-		
+        
                 if ($this->success && $baStatus['State'] === 'Open') {
                     $response = $this->authorizeOnBillingAgreement($authorizeParameters);
                 }
-		
-		if($baStatus['State'] != 'Open' && $baStatus['State'] != 'Draft') {
-		    throw new \Exception('The Billing Agreement is in the ' . $baStatus['State'] . " State. It should be in the Draft or Open State");
-		}
-		
-            return $response;
-	    }
-	}
+        
+                if ($baStatus['State'] != 'Open' && $baStatus['State'] != 'Draft') {
+                    throw new \Exception('The Billing Agreement is in the ' . $baStatus['State'] . " State. It should be in the Draft or Open State");
+                }
+        
+                return $response;
+
+            default:
+                throw new \Exception('Invalid Charge Type');
+        }
+    }
+
 
     /* GetProviderCreditDetails API Call - Get the details of the Provider Credit.
@@ -1249,21 +1568,20 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getProviderCreditDetails($requestParameters = array())
     {
-	$parameters           = array();
+        $parameters           = array();
         $parameters['Action'] = 'GetProviderCreditDetails';
         $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
 
         $fieldMappings = array(
-            'merchant_id' 		=> 'SellerId',
+            'merchant_id'               => 'SellerId',
             'amazon_provider_credit_id' => 'AmazonProviderCreditId',
-            'mws_auth_token' 		=> 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'mws_auth_token'            => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* GetProviderCreditReversalDetails API Call - Get details of the Provider Credit Reversal.
@@ -1273,21 +1591,20 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function getProviderCreditReversalDetails($requestParameters = array())
     {
-	$parameters           = array();
+        $parameters           = array();
         $parameters['Action'] = 'GetProviderCreditReversalDetails';
         $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
 
         $fieldMappings = array(
-            'merchant_id' 		  	 => 'SellerId',
+            'merchant_id'                        => 'SellerId',
             'amazon_provider_credit_reversal_id' => 'AmazonProviderCreditReversalId',
-            'mws_auth_token' 		  	 => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'mws_auth_token'                     => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* ReverseProviderCredit API Call - Reverse the Provider Credit.
@@ -1301,25 +1618,24 @@
      * @optional requestParameters['mws_auth_token'] - [String]
      */
-
     public function reverseProviderCredit($requestParameters = array())
     {
-	$parameters           = array();
+        $parameters           = array();
         $parameters['Action'] = 'ReverseProviderCredit';
         $requestParameters    = array_change_key_case($requestParameters, CASE_LOWER);
 
         $fieldMappings = array(
-            'merchant_id' 		   => 'SellerId',
+            'merchant_id'                  => 'SellerId',
             'amazon_provider_credit_id'    => 'AmazonProviderCreditId',
-	    'credit_reversal_reference_id' => 'CreditReversalReferenceId',
-	    'credit_reversal_amount' 	   => 'CreditReversalAmount.Amount',
-	    'currency_code' 		   => 'CreditReversalAmount.CurrencyCode',
-	    'credit_reversal_note' 	   => 'CreditReversalNote',
-            'mws_auth_token' 		   => 'MWSAuthToken'
-        );
-
-        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
-
-        return ($responseObject);
-    }
+            'credit_reversal_reference_id' => 'CreditReversalReferenceId',
+            'credit_reversal_amount'       => 'CreditReversalAmount.Amount',
+            'currency_code'                => 'CreditReversalAmount.CurrencyCode',
+            'credit_reversal_note'         => 'CreditReversalNote',
+            'mws_auth_token'               => 'MWSAuthToken'
+        );
+
+        $responseObject = $this->setParametersAndPost($parameters, $fieldMappings, $requestParameters);
+        return ($responseObject);
+    }
+
 
     /* Create an Array of required parameters, sort them
@@ -1332,9 +1648,22 @@
      * @param Signature [String]
      */
-
     private function calculateSignatureAndParametersToString($parameters = array())
     {
+        foreach ($parameters as $key => $value) {
+            // Ensure that no unexpected type coercions have happened
+            if ($key === 'CaptureNow' || $key === 'ConfirmNow' || $key === 'InheritShippingAddress' || $key === 'RequestPaymentAuthorization') {
+                if (!is_bool($value)) {
+                    throw new \Exception($key . ' value ' . $value . ' is of type ' . gettype($value) . ' and should be a boolean value');
+                }
+            }
+
+            // Ensure boolean values are outputed as 'true' or 'false'
+            if (is_bool($value)) {
+                $parameters[$key] = json_encode($value);
+            }
+        }
+
         $parameters['AWSAccessKeyId']   = $this->config['access_key'];
-        $parameters['Version']          = self::SERVICE_VERSION;
+        $parameters['Version']          = self::MWS_VERSION;
         $parameters['SignatureMethod']  = 'HmacSHA256';
         $parameters['SignatureVersion'] = 2;
@@ -1347,8 +1676,10 @@
         $parameters              = $this->getParametersAsString($parameters);
 
-	// Save these parameters in the parameters variable so that it can be returned for unit testing.
-	$this->parameters 	 = $parameters;
+        // Save these parameters in the parameters variable so that it can be returned for unit testing.
+        $this->parameters = $parameters;
+
         return $parameters;
     }
+
 
     /* Computes RFC 2104-compliant HMAC signature for request parameters
@@ -1381,5 +1712,4 @@
      *
      */
-
     private function signParameters(array $parameters)
     {
@@ -1398,9 +1728,9 @@
     }
 
+
     /* Calculate String to Sign for SignatureVersion 2
      * @param array $parameters request parameters
      * @return String to Sign
      */
-
     private function calculateStringToSignV2(array $parameters)
     {
@@ -1412,9 +1742,12 @@
         $data .= "\n";
         $data .= $this->getParametersAsString($parameters);
+
+        $this->logMessage($this->sanitizeRequestData($data));
+
         return $data;
     }
 
+
     /* Convert paremeters to Url encoded query string */
-
     private function getParametersAsString(array $parameters)
     {
@@ -1425,5 +1758,7 @@
 
         return implode('&', $queryParameters);
-    }
+
+    }
+
 
     private function urlEncode($value)
@@ -1432,6 +1767,6 @@
     }
 
+
     /* Computes RFC 2104-compliant HMAC signature */
-
     private function sign($data, $algorithm)
     {
@@ -1447,10 +1782,11 @@
     }
 
+
     /* Formats date as ISO 8601 timestamp */
-
     private function getFormattedTimestamp()
     {
         return gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
     }
+
 
     /* invokePost takes the parameters and invokes the httpPost function to POST the parameters
@@ -1458,5 +1794,4 @@
      * The response from the POST is an XML which is converted to Array
      */
-
     private function invokePost($parameters)
     {
@@ -1465,6 +1800,6 @@
         $this->success = false;
 
-    // Submit the request and read response body
-    try {
+        // Submit the request and read response body
+        try {
             $shouldRetry = true;
             $retries     = 0;
@@ -1472,11 +1807,9 @@
                 try {
                     $this->constructUserAgentHeader();
-
                     $httpCurlRequest = new HttpCurl($this->config);
                     $response = $httpCurlRequest->httpPost($this->mwsServiceUrl, $this->userAgent, $parameters);
                     $curlResponseInfo = $httpCurlRequest->getCurlResponseInfo();
-                    
                     $statusCode = $curlResponseInfo["http_code"];
-                    
+                    $this->logMessage($this->userAgent);
                     $response = array(
                         'Status' => $statusCode,
@@ -1485,11 +1818,10 @@
 
                     $statusCode = $response['Status'];
-                    
-            if ($statusCode == 200) {
+                    if ($statusCode == 200) {
                         $shouldRetry    = false;
                         $this->success = true;
                     } elseif ($statusCode == 500 || $statusCode == 503) {
 
-            $shouldRetry = true;
+                        $shouldRetry = true;
                         if ($shouldRetry && strtolower($this->config['handle_throttle'])) {
                             $this->pauseOnRetry(++$retries, $statusCode);
@@ -1506,16 +1838,23 @@
         }
 
+        $this->logMessage($this->sanitizeResponseData($response['ResponseBody']));
         return $response;
     }
 
+
     /* Exponential sleep on failed request
+     * Up to three retries will occur if first reqest fails
+     * after 1.0 second, 2.2 seconds, and finally 7.0 seconds
      * @param retries current retry
      * @throws Exception if maximum number of retries has been reached
      */
-
     private function pauseOnRetry($retries, $status)
     {
         if ($retries <= self::MAX_ERROR_RETRY) {
-            $delay = (int) (pow(4, $retries) * 100000);
+            // PHP delays are in microseconds (1 million microsecond = 1 sec)
+            // 1st delay is (4^1) * 100000 + 600000 = 0.4 + 0.6 second = 1.0 sec
+            // 2nd delay is (4^2) * 100000 + 600000 = 1.6 + 0.6 second = 2.2 sec
+            // 3rd delay is (4^3) * 100000 + 600000 = 6.4 + 0.6 second = 7.0 sec
+            $delay = (int) (pow(4, $retries) * 100000) + 600000;
             usleep($delay);
         } else {
@@ -1524,6 +1863,6 @@
     }
 
+
     /* Create MWS service URL and the Endpoint path */
-
     private function createServiceUrl()
     {
@@ -1533,7 +1872,13 @@
             $region = strtolower($this->config['region']);
             if (array_key_exists($region, $this->regionMappings)) {
-                $this->mwsEndpointUrl  = $this->mwsServiceUrls[$this->regionMappings[$region]];
-                $this->mwsServiceUrl   = 'https://' . $this->mwsEndpointUrl . '/' . $this->modePath . '/' . self::SERVICE_VERSION;
-                $this->mwsEndpointPath = '/' . $this->modePath . '/' . self::SERVICE_VERSION;
+
+                if (!is_null($this->config['override_service_url'])) {
+                    $this->mwsEndpointUrl  = preg_replace("(https?://)", "", $this->config['override_service_url']);
+                } else {
+                    $this->mwsEndpointUrl  = $this->mwsServiceUrls[$this->regionMappings[$region]];
+                }
+
+                $this->mwsServiceUrl   = 'https://' . $this->mwsEndpointUrl . '/' . $this->modePath . '/' . self::MWS_VERSION;
+                $this->mwsEndpointPath = '/' . $this->modePath . '/' . self::MWS_VERSION;
             } else {
                 throw new \Exception($region . ' is not a valid region');
@@ -1544,36 +1889,49 @@
     }
 
+
     /* Based on the config['region'] and config['sandbox'] values get the user profile URL */
-
     private function profileEndpointUrl()
     {
-	$profileEnvt = strtolower($this->config['sandbox']) ? "api.sandbox" : "api";
-	
+        $profileEnvt = strtolower($this->config['sandbox']) ? "api.sandbox" : "api";
+    
         if (!empty($this->config['region'])) {
             $region = strtolower($this->config['region']);
 
-	    if (array_key_exists($region, $this->regionMappings) ) {
+            if (array_key_exists($region, $this->regionMappings) ) {
                 $this->profileEndpoint = 'https://' . $profileEnvt . '.' . $this->profileEndpointUrls[$region];
-	    }else{
-		throw new \Exception($region . ' is not a valid region');
-	    }
-	} else {
+            } else {
+                throw new \Exception($region . ' is not a valid region');
+            }
+        } else {
             throw new \Exception("config['region'] is a required parameter and is not set");
         }
     }
 
+
     /* Create the User Agent Header sent with the POST request */
-
-    private function constructUserAgentHeader()
-    {
-        $this->userAgent = $this->quoteApplicationName($this->config['application_name']) . '/' . $this->quoteApplicationVersion($this->config['application_version']);
-        $this->userAgent .= ' (';
-        $this->userAgent .= 'Language=PHP/' . phpversion();
-        $this->userAgent .= '; ';
-        $this->userAgent .= 'Platform=' . php_uname('s') . '/' . php_uname('m') . '/' . php_uname('r');
-        $this->userAgent .= '; ';
-        $this->userAgent .= 'MWSClientVersion=' . self::MWS_CLIENT_VERSION;
+    /* Protected because of PSP module usaged */
+    protected function constructUserAgentHeader()
+    {
+        $this->userAgent = 'amazon-pay-sdk-php/' . self::SDK_VERSION . ' (';
+
+        if (($this->config['application_name']) || ($this->config['application_version'])) {
+            if ($this->config['application_name']) {
+                $this->userAgent .= $this->quoteApplicationName($this->config['application_name']);
+                if ($this->config['application_version']) {
+                    $this->userAgent .= '/';
+                }
+            }
+          
+            if ($this->config['application_version']) {
+                $this->userAgent .= $this->quoteApplicationVersion($this->config['application_version']);
+            }
+            $this->userAgent .= '; ';
+        }
+
+        $this->userAgent .= 'PHP/' . phpversion() . '; ';
+        $this->userAgent .= php_uname('s') . '/' . php_uname('m') . '/' . php_uname('r');
         $this->userAgent .= ')';
     }
+
 
     /* Collapse multiple whitespace characters into a single ' ' and backslash escape '\',
@@ -1582,5 +1940,4 @@
      * @return string
      */
-
     private function quoteApplicationName($s)
     {
@@ -1591,4 +1948,5 @@
     }
 
+
     /* Collapse multiple whitespace characters into a single ' ' and backslash escape '\',
      * and '(' characters from a string.
@@ -1597,5 +1955,4 @@
      * @return string
      */
-
     private function quoteApplicationVersion($s)
     {
@@ -1605,3 +1962,55 @@
         return $quotedString;
     }
+
+
+    private function sanitizeRequestData($input)
+    {
+        $patterns = array();
+        $patterns[0] = '/(SellerNote=)(.+)(&)/ms';
+        $patterns[1] = '/(SellerAuthorizationNote=)(.+)(&)/ms';
+        $patterns[2] = '/(SellerCaptureNote=)(.+)(&)/ms';
+        $patterns[3] = '/(SellerRefundNote=)(.+)(&)/ms';
+
+        $replacements = array();
+        $replacements[0] = '$1REMOVED$3';
+        $replacements[1] = '$1REMOVED$3';
+        $replacements[2] = '$1REMOVED$3';
+        $replacements[3] = '$1REMOVED$3';
+
+        return preg_replace($patterns, $replacements, $input);
+    }
+
+
+    private function sanitizeResponseData($input)
+    {
+        $patterns = array();
+        $patterns[0] = '/(<Buyer>)(.+)(<\/Buyer>)/ms';
+        $patterns[1] = '/(<PhysicalDestination>)(.+)(<\/PhysicalDestination>)/ms';
+        $patterns[2] = '/(<BillingAddress>)(.+)(<\/BillingAddress>)/ms';
+        $patterns[3] = '/(<SellerNote>)(.+)(<\/SellerNote>)/ms';
+        $patterns[4] = '/(<AuthorizationBillingAddress>)(.+)(<\/AuthorizationBillingAddress>)/ms';
+        $patterns[5] = '/(<SellerAuthorizationNote>)(.+)(<\/SellerAuthorizationNote>)/ms';
+        $patterns[6] = '/(<SellerCaptureNote>)(.+)(<\/SellerCaptureNote>)/ms';
+        $patterns[7] = '/(<SellerRefundNote>)(.+)(<\/SellerRefundNote>)/ms';
+
+        $replacements = array();
+        $replacements[0] = '$1 REMOVED $3';
+        $replacements[1] = '$1 REMOVED $3';
+        $replacements[2] = '$1 REMOVED $3';
+        $replacements[3] = '$1 REMOVED $3';
+        $replacements[4] = '$1 REMOVED $3';
+        $replacements[5] = '$1 REMOVED $3';
+        $replacements[6] = '$1 REMOVED $3';
+        $replacements[7] = '$1 REMOVED $3';
+
+        return preg_replace($patterns, $replacements, $input);
+    }
+
+
+    /* Computes RFC 2104-compliant HMAC signature */
+    public static function getSignature($stringToSign, $secretKey)
+    {
+        return base64_encode(hash_hmac('sha256', $stringToSign, $secretKey, true));
+    }
+
 }
Index: /mods/mod_amazon/PayWithAmazon/HttpCurl.php
===================================================================
--- /mods/mod_amazon/PayWithAmazon/HttpCurl.php	(revision 7755)
+++ /mods/mod_amazon/PayWithAmazon/HttpCurl.php	(revision 7756)
@@ -1,4 +1,4 @@
 <?php
-namespace PayWithAmazon;
+namespace AmazonPay;
 
 /* Class HttpCurl
@@ -6,5 +6,5 @@
  */
 
-require_once 'Interface.php';
+require_once 'HttpCurlInterface.php';
 
 class HttpCurl implements HttpCurlInterface
@@ -14,23 +14,24 @@
     private $accessToken = null;
     private $curlResponseInfo = null;
-    
+    private $headerArray = array();
+
     /* Takes user configuration array as input
      * Takes configuration for API call or IPN config
      */
-    
+
     public function __construct($config = null)
     {
         $this->config = $config;
     }
-    
+
     /* Setter for boolean header to get the user info */
-    
+
     public function setHttpHeader()
     {
         $this->header = true;
     }
-    
+
     /* Setter for Access token to get the user info */
-    
+
     public function setAccessToken($accesstoken)
     {
@@ -46,6 +47,6 @@
      * config['proxy_password']
      */
-    
-    private  function commonCurlParams($url,$userAgent)
+
+    protected function commonCurlParams($url,$userAgent)
     {
         $ch = curl_init();
@@ -55,23 +56,23 @@
         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-        
+
         if (!is_null($this->config['cabundle_file'])) {
             curl_setopt($ch, CURLOPT_CAINFO, $this->config['cabundle_file']);
         }
-        
+
         if (!empty($userAgent))
             curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
-        
+
         if ($this->config['proxy_host'] != null && $this->config['proxy_port'] != -1) {
             curl_setopt($ch, CURLOPT_PROXY, $this->config['proxy_host'] . ':' . $this->config['proxy_port']);
         }
-        
+
         if ($this->config['proxy_username'] != null && $this->config['proxy_password'] != null) {
             curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->config['proxy_username'] . ':' . $this->config['proxy_password']);
         }
-        
+
         return $ch;
     }
-    
+
     /* POST using curl for the following situations
      * 1. API calls
@@ -79,53 +80,50 @@
      * 3. Get User Info
      */
-    
+
     public function httpPost($url, $userAgent = null, $parameters = null)
     {
         $ch = $this->commonCurlParams($url,$userAgent);
-        
+      
         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
         curl_setopt($ch, CURLOPT_HEADER, false);
-        
         $response = $this->execute($ch);
         return $response;
     }
-    
+
     /* GET using curl for the following situations
      * 1. IPN certificate retrieval
      * 2. Get User Info
      */
-    
+
     public function httpGet($url, $userAgent = null)
     {
         $ch = $this->commonCurlParams($url,$userAgent);
-        
+
         // Setting the HTTP header with the Access Token only for Getting user info
         if ($this->header) {
-            curl_setopt($ch, CURLOPT_HTTPHEADER, array(
-                'Authorization: bearer ' . $this->accessToken
-            ));
+            $this->headerArray[] = 'Authorization: bearer ' . $this->accessToken;
         }
-        
+
         $response = $this->execute($ch);
         return $response;
     }
-    
+
     /* Execute Curl request */
-    
-    private function execute($ch)
-	{
-		
-		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
-		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
-		
+    /* Protected because will be used by PSP module */
+    protected function execute($ch)
+    {
         $response = '';
+
+        // Ensure we never send the "Expect: 100-continue" header
+        $this->headerArray[] = 'Expect:';
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headerArray);
+
         $response = curl_exec($ch);
-        if (!$response = curl_exec($ch)) {
+        if ($response === false) {
             $error_msg = "Unable to post request, underlying exception of " . curl_error($ch);
             curl_close($ch);
             throw new \Exception($error_msg);
-        }
-        else{
+        } else {
             $this->curlResponseInfo = curl_getinfo($ch);
         }
@@ -133,7 +131,7 @@
         return $response;
     }
-    
+
     /* Get the output of Curl Getinfo */
-    
+
     public function getCurlResponseInfo()
     {
Index: /mods/mod_amazon/PayWithAmazon/IpnHandler.php
===================================================================
--- /mods/mod_amazon/PayWithAmazon/IpnHandler.php	(revision 7755)
+++ /mods/mod_amazon/PayWithAmazon/IpnHandler.php	(revision 7756)
@@ -1,4 +1,4 @@
 <?php
-namespace PayWithAmazon;
+namespace AmazonPay;
 
 /* Class IPN_Handler
@@ -8,6 +8,15 @@
 
 require_once 'HttpCurl.php';
-require_once 'Interface.php';
-class IpnHandler implements IpnHandlerInterface
+require_once 'IpnHandlerInterface.php';
+if (!interface_exists('\Psr\Log\LoggerAwareInterface')) {
+    require_once(__DIR__.'/../Psr/Log/LoggerAwareInterface.php');
+}
+if (!interface_exists('\Psr\Log\LoggerInterface')) {
+    require_once(__DIR__.'/../Psr/Log/LoggerInterface.php');
+}
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+
+class IpnHandler implements IpnHandlerInterface, LoggerAwareInterface
 {
 
@@ -19,10 +28,14 @@
     private $certificate = null;
     private $expectedCnName = 'sns.amazonaws.com';
+    private $defaultHostPattern = '/^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/';
+
+    // Implement a logging library that utilizes the PSR 3 logger interface
+    private $logger = null;
 
     private $ipnConfig = array('cabundle_file'  => null,
-			       'proxy_host' 	=> null,
-                               'proxy_port' 	=> -1,
+                   'proxy_host'     => null,
+                               'proxy_port'     => -1,
                                'proxy_username' => null,
-			       'proxy_password' => null);
+                   'proxy_password' => null);
 
 
@@ -62,5 +75,5 @@
     {
         $ipnConfig = array_change_key_case($ipnConfig, CASE_LOWER);
-	$ipnConfig = $this->trimArray($ipnConfig);
+    $ipnConfig = $this->trimArray($ipnConfig);
 
         foreach ($ipnConfig as $key => $value) {
@@ -69,6 +82,18 @@
             } else {
                 throw new \Exception('Key ' . $key . ' is either not part of the configuration or has incorrect Key name.
-				check the ipnConfig array key names to match your key names of your config array ', 1);
+                check the ipnConfig array key names to match your key names of your config array ', 1);
             }
+        }
+    }
+
+    public function setLogger(LoggerInterface $logger = null) {
+        $this->logger = $logger;
+    }
+    
+    /* Helper function to log data within the Client */
+
+    private function logMessage($message) {
+        if ($this->logger) {
+            $this->logger->debug($message);
         }
     }
@@ -104,13 +129,14 @@
     private function trimArray($array)
     {
-	foreach ($array as $key => $value)
-	{
-	    $array[$key] = trim($value);
-	}
-	return $array;
+    foreach ($array as $key => $value)
+    {
+        $array[$key] = trim($value);
+    }
+    return $array;
     }
     
     private function validateHeaders()
     {
+
         // Quickly check that this is a sns message
         if (!array_key_exists('x-amz-sns-message-type', $this->headers)) {
@@ -203,5 +229,26 @@
              */
             $this->signatureFields = implode("\n", $signatureFields) . "\n";
-
+        }
+    }
+
+    /* Ensures that the URL of the certificate is one belonging to AWS.
+     *
+     * @param string $url Certificate URL
+     *
+     * @throws InvalidSnsMessageException if the cert url is invalid.
+     */
+
+    private function validateUrl($url)
+    {
+        $parsed = parse_url($url);
+        if (empty($parsed['scheme'])
+            || empty($parsed['host'])
+            || $parsed['scheme'] !== 'https'
+            || substr($url, -4) !== '.pem'
+            || !preg_match($this->defaultHostPattern, $parsed['host'])
+        ) {
+            throw new \Exception(
+                'The certificate is located on an invalid domain.'
+            );
         }
     }
@@ -210,5 +257,4 @@
      * public key
      *
-     * @param string $data            data to validate
      * @param string $signature       decoded signature to compare against
      * @param string $certificatePath path to certificate, can be file or url
@@ -221,7 +267,7 @@
     private function constructAndVerifySignature()
     {
-	$signature       = base64_decode($this->getMandatoryField("Signature"));
+    $signature       = base64_decode($this->getMandatoryField("Signature"));
         $certificatePath = $this->getMandatoryField("SigningCertURL");
-
+        $this->validateUrl($certificatePath);
         $this->certificate = $this->getCertificate($certificatePath);
 
@@ -241,5 +287,5 @@
         $httpCurlRequest  = new HttpCurl($this->ipnConfig);
 
-	$response = $httpCurlRequest->httpGet($certificatePath);
+    $response = $httpCurlRequest->httpGet($certificatePath);
 
         return $response;
@@ -248,5 +294,4 @@
     /* Verify that the signature is correct for the given data and public key
      *
-     * @param string $data            data to validate
      * @param string $signature       decoded signature to compare against
      * @param string $certificate     certificate object defined in Certificate.php
@@ -387,4 +432,7 @@
         $ipnMessage = $this->returnMessage();
 
+        $this->logMessage(sprintf('IPN received for merchant account: %s', $this->sanitizeResponseData($ipnMessage['SellerId'])));
+        $this->logMessage($this->sanitizeResponseData($ipnMessage['NotificationData']));
+
         // Getting the Simple XML element object of the IPN XML Response Body
         $response = simplexml_load_string((string) $ipnMessage['NotificationData']);
@@ -414,3 +462,23 @@
         return $remainingFields;
     }
+
+    private function sanitizeResponseData($input)
+    {
+
+        $patterns = array();
+        $patterns[0] = '/(<SellerNote>)(.+)(<\/SellerNote>)/ms';
+        $patterns[1] = '/(<AuthorizationBillingAddress>)(.+)(<\/AuthorizationBillingAddress>)/ms';
+        $patterns[2] = '/(<SellerAuthorizationNote>)(.+)(<\/SellerAuthorizationNote>)/ms';
+        $patterns[3] = '/(<SellerCaptureNote>)(.+)(<\/SellerCaptureNote>)/ms';
+        $patterns[4] = '/(<SellerRefundNote>)(.+)(<\/SellerRefundNote>)/ms';
+
+        $replacements = array();
+        $replacements[0] = '$1 REMOVED $3';
+        $replacements[1] = '$1 REMOVED $3';
+        $replacements[2] = '$1 REMOVED $3';
+        $replacements[3] = '$1 REMOVED $3';
+        $replacements[4] = '$1 REMOVED $3';
+
+        return preg_replace($patterns, $replacements, $input);
+    }
 }
Index: /mods/mod_amazon/PayWithAmazon/Regions.php
===================================================================
--- /mods/mod_amazon/PayWithAmazon/Regions.php	(revision 7755)
+++ /mods/mod_amazon/PayWithAmazon/Regions.php	(revision 7756)
@@ -1,4 +1,4 @@
 <?php
-namespace PayWithAmazon;
+namespace AmazonPay;
 
 /* Class Regions
Index: /mods/mod_amazon/PayWithAmazon/ResponseParser.php
===================================================================
--- /mods/mod_amazon/PayWithAmazon/ResponseParser.php	(revision 7755)
+++ /mods/mod_amazon/PayWithAmazon/ResponseParser.php	(revision 7756)
@@ -1,4 +1,4 @@
 <?php
-namespace PayWithAmazon;
+namespace AmazonPay;
 
 /* ResponseParser
@@ -6,5 +6,5 @@
  */
 
-require_once 'Interface.php';
+require_once 'ResponseInterface.php';
 
 class ResponseParser implements ResponseInterface
@@ -69,15 +69,7 @@
     public function getOrderReferenceDetailsStatus($response)
     {
-       $data= new \SimpleXMLElement($response);
-        $namespaces = $data->getNamespaces(true);
-        foreach($namespaces as $key=>$value){
-            $namespace = $value;
-        }
-        $data->registerXPathNamespace('GetORO', $namespace);
-        foreach ($data->xpath('//GetORO:OrderReferenceStatus') as $value) {
-            $oroStatus = json_decode(json_encode((array)$value), TRUE);
-        }
-        
-        return $oroStatus ;
+       $oroStatus = $this->getStatus('GetORO', '//GetORO:OrderReferenceStatus', $response);
+               
+       return $oroStatus;
     }
     
@@ -86,15 +78,22 @@
     public function getBillingAgreementDetailsStatus($response)
     {
+       $baStatus = $this->getStatus('GetBA', '//GetBA:BillingAgreementStatus', $response);  
+       
+       return $baStatus;
+    }
+    
+    private function getStatus($type, $path, $response) 
+    {
        $data= new \SimpleXMLElement($response);
-        $namespaces = $data->getNamespaces(true);
-        foreach($namespaces as $key=>$value){
-            $namespace = $value;
-        }
-        $data->registerXPathNamespace('GetBA', $namespace);
-        foreach ($data->xpath('//GetBA:BillingAgreementStatus') as $value) {
-            $baStatus = json_decode(json_encode((array)$value), TRUE);
-        }
-        
-        return $baStatus ;
+       $namespaces = $data->getNamespaces(true);
+       foreach($namespaces as $key=>$value){
+           $namespace = $value;
+       }
+       $data->registerXPathNamespace($type, $namespace);
+       foreach ($data->xpath($path) as $value) {
+           $status = json_decode(json_encode((array)$value), TRUE);
+       }
+       
+       return $status;
     }
 }
Index: /mods/mod_amazon/Psr/Log/AbstractLogger.php
===================================================================
--- /mods/mod_amazon/Psr/Log/AbstractLogger.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/AbstractLogger.php	(revision 7756)
@@ -0,0 +1,128 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This is a simple Logger implementation that other Loggers can inherit from.
+ *
+ * It simply delegates all log-level-specific methods to the `log` method to
+ * reduce boilerplate code that a simple Logger that does the same thing with
+ * messages regardless of the error level has to implement.
+ */
+abstract class AbstractLogger implements LoggerInterface
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function emergency($message, array $context = array())
+    {
+        $this->log(LogLevel::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function alert($message, array $context = array())
+    {
+        $this->log(LogLevel::ALERT, $message, $context);
+    }
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function critical($message, array $context = array())
+    {
+        $this->log(LogLevel::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function error($message, array $context = array())
+    {
+        $this->log(LogLevel::ERROR, $message, $context);
+    }
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function warning($message, array $context = array())
+    {
+        $this->log(LogLevel::WARNING, $message, $context);
+    }
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function notice($message, array $context = array())
+    {
+        $this->log(LogLevel::NOTICE, $message, $context);
+    }
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function info($message, array $context = array())
+    {
+        $this->log(LogLevel::INFO, $message, $context);
+    }
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function debug($message, array $context = array())
+    {
+        $this->log(LogLevel::DEBUG, $message, $context);
+    }
+}
Index: /mods/mod_amazon/Psr/Log/InvalidArgumentException.php
===================================================================
--- /mods/mod_amazon/Psr/Log/InvalidArgumentException.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/InvalidArgumentException.php	(revision 7756)
@@ -0,0 +1,7 @@
+<?php
+
+namespace Psr\Log;
+
+class InvalidArgumentException extends \InvalidArgumentException
+{
+}
Index: /mods/mod_amazon/Psr/Log/LogLevel.php
===================================================================
--- /mods/mod_amazon/Psr/Log/LogLevel.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/LogLevel.php	(revision 7756)
@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes log levels.
+ */
+class LogLevel
+{
+    const EMERGENCY = 'emergency';
+    const ALERT     = 'alert';
+    const CRITICAL  = 'critical';
+    const ERROR     = 'error';
+    const WARNING   = 'warning';
+    const NOTICE    = 'notice';
+    const INFO      = 'info';
+    const DEBUG     = 'debug';
+}
Index: /mods/mod_amazon/Psr/Log/LoggerAwareInterface.php
===================================================================
--- /mods/mod_amazon/Psr/Log/LoggerAwareInterface.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/LoggerAwareInterface.php	(revision 7756)
@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes a logger-aware instance.
+ */
+interface LoggerAwareInterface
+{
+    /**
+     * Sets a logger instance on the object.
+     *
+     * @param LoggerInterface $logger
+     *
+     * @return null
+     */
+    public function setLogger(LoggerInterface $logger);
+}
Index: /mods/mod_amazon/Psr/Log/LoggerAwareTrait.php
===================================================================
--- /mods/mod_amazon/Psr/Log/LoggerAwareTrait.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/LoggerAwareTrait.php	(revision 7756)
@@ -0,0 +1,26 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Basic Implementation of LoggerAwareInterface.
+ */
+trait LoggerAwareTrait
+{
+    /**
+     * The logger instance.
+     *
+     * @var LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * Sets a logger.
+     *
+     * @param LoggerInterface $logger
+     */
+    public function setLogger(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+}
Index: /mods/mod_amazon/Psr/Log/LoggerInterface.php
===================================================================
--- /mods/mod_amazon/Psr/Log/LoggerInterface.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/LoggerInterface.php	(revision 7756)
@@ -0,0 +1,123 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes a logger instance.
+ *
+ * The message MUST be a string or object implementing __toString().
+ *
+ * The message MAY contain placeholders in the form: {foo} where foo
+ * will be replaced by the context data in key "foo".
+ *
+ * The context array can contain arbitrary data. The only assumption that
+ * can be made by implementors is that if an Exception instance is given
+ * to produce a stack trace, it MUST be in a key named "exception".
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
+ * for the full interface specification.
+ */
+interface LoggerInterface
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function emergency($message, array $context = array());
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function alert($message, array $context = array());
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function critical($message, array $context = array());
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function error($message, array $context = array());
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function warning($message, array $context = array());
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function notice($message, array $context = array());
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function info($message, array $context = array());
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function debug($message, array $context = array());
+
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function log($level, $message, array $context = array());
+}
Index: /mods/mod_amazon/Psr/Log/LoggerTrait.php
===================================================================
--- /mods/mod_amazon/Psr/Log/LoggerTrait.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/LoggerTrait.php	(revision 7756)
@@ -0,0 +1,140 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This is a simple Logger trait that classes unable to extend AbstractLogger
+ * (because they extend another class, etc) can include.
+ *
+ * It simply delegates all log-level-specific methods to the `log` method to
+ * reduce boilerplate code that a simple Logger that does the same thing with
+ * messages regardless of the error level has to implement.
+ */
+trait LoggerTrait
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function emergency($message, array $context = array())
+    {
+        $this->log(LogLevel::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function alert($message, array $context = array())
+    {
+        $this->log(LogLevel::ALERT, $message, $context);
+    }
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function critical($message, array $context = array())
+    {
+        $this->log(LogLevel::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function error($message, array $context = array())
+    {
+        $this->log(LogLevel::ERROR, $message, $context);
+    }
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function warning($message, array $context = array())
+    {
+        $this->log(LogLevel::WARNING, $message, $context);
+    }
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function notice($message, array $context = array())
+    {
+        $this->log(LogLevel::NOTICE, $message, $context);
+    }
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function info($message, array $context = array())
+    {
+        $this->log(LogLevel::INFO, $message, $context);
+    }
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function debug($message, array $context = array())
+    {
+        $this->log(LogLevel::DEBUG, $message, $context);
+    }
+
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    abstract public function log($level, $message, array $context = array());
+}
Index: /mods/mod_amazon/Psr/Log/NullLogger.php
===================================================================
--- /mods/mod_amazon/Psr/Log/NullLogger.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/NullLogger.php	(revision 7756)
@@ -0,0 +1,28 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This Logger can be used to avoid conditional log calls.
+ *
+ * Logging should always be optional, and if no logger is provided to your
+ * library creating a NullLogger instance to have something to throw logs at
+ * is a good way to avoid littering your code with `if ($this->logger) { }`
+ * blocks.
+ */
+class NullLogger extends AbstractLogger
+{
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return null
+     */
+    public function log($level, $message, array $context = array())
+    {
+        // noop
+    }
+}
Index: /mods/mod_amazon/Psr/Log/Test/LoggerInterfaceTest.php
===================================================================
--- /mods/mod_amazon/Psr/Log/Test/LoggerInterfaceTest.php	(revision 7756)
+++ /mods/mod_amazon/Psr/Log/Test/LoggerInterfaceTest.php	(revision 7756)
@@ -0,0 +1,133 @@
+<?php
+
+namespace Psr\Log\Test;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * Provides a base test class for ensuring compliance with the LoggerInterface.
+ *
+ * Implementors can extend the class and implement abstract methods to run this
+ * as part of their test suite.
+ */
+abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @return LoggerInterface
+     */
+    abstract public function getLogger();
+
+    /**
+     * This must return the log messages in order.
+     *
+     * The simple formatting of the messages is: "<LOG LEVEL> <MESSAGE>".
+     *
+     * Example ->error('Foo') would yield "error Foo".
+     *
+     * @return string[]
+     */
+    abstract public function getLogs();
+
+    public function testImplements()
+    {
+        $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
+    }
+
+    /**
+     * @dataProvider provideLevelsAndMessages
+     */
+    public function testLogsAtAllLevels($level, $message)
+    {
+        $logger = $this->getLogger();
+        $logger->{$level}($message, array('user' => 'Bob'));
+        $logger->log($level, $message, array('user' => 'Bob'));
+
+        $expected = array(
+            $level.' message of level '.$level.' with context: Bob',
+            $level.' message of level '.$level.' with context: Bob',
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function provideLevelsAndMessages()
+    {
+        return array(
+            LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
+            LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
+            LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
+            LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
+            LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
+            LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
+            LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
+            LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
+        );
+    }
+
+    /**
+     * @expectedException \Psr\Log\InvalidArgumentException
+     */
+    public function testThrowsOnInvalidLevel()
+    {
+        $logger = $this->getLogger();
+        $logger->log('invalid level', 'Foo');
+    }
+
+    public function testContextReplacement()
+    {
+        $logger = $this->getLogger();
+        $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
+
+        $expected = array('info {Message {nothing} Bob Bar a}');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testObjectCastToString()
+    {
+        $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
+        $dummy->expects($this->once())
+            ->method('__toString')
+            ->will($this->returnValue('DUMMY'));
+
+        $this->getLogger()->warning($dummy);
+
+        $expected = array('warning DUMMY');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextCanContainAnything()
+    {
+        $context = array(
+            'bool' => true,
+            'null' => null,
+            'string' => 'Foo',
+            'int' => 0,
+            'float' => 0.5,
+            'nested' => array('with object' => new DummyTest),
+            'object' => new \DateTime,
+            'resource' => fopen('php://memory', 'r'),
+        );
+
+        $this->getLogger()->warning('Crazy context data', $context);
+
+        $expected = array('warning Crazy context data');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextExceptionKeyCanBeExceptionOrOtherValues()
+    {
+        $logger = $this->getLogger();
+        $logger->warning('Random message', array('exception' => 'oops'));
+        $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
+
+        $expected = array(
+            'warning Random message',
+            'critical Uncaught Exception!'
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+}
+
+class DummyTest
+{
+}
Index: /mods/wpsg_mod_amazon.class.php
===================================================================
--- /mods/wpsg_mod_amazon.class.php	(revision 7755)
+++ /mods/wpsg_mod_amazon.class.php	(revision 7756)
@@ -45,8 +45,7 @@
         } // public function install()
 
-        public function settings_edit()
-        {
-
-            $this->shop->view['ipnURL'] = $this->shop->getUrl(wpsg_ShopController::URL_BASKET, 'wpsg_mod_amazon', 'ipn');
+        public function settings_edit() {
+
+            $this->shop->view['ipnURL'] = $this->shop->getUrl(wpsg_ShopController::URL_BASKET, 'wpsg_mod_amazon', 'ipn', [], true);
             $this->shop->view['jsOrigin'] = preg_replace('/^http:\/\//i', 'https://', $this->shop->get_option('siteurl'));
 
@@ -54,4 +53,19 @@
 
         } // public function settings_edit()
+
+        public function order_view_afterpayment(&$order_id) {
+
+            $oOrder = wpsg_order::getInstance($order_id);
+
+            if ($oOrder->getPaymentID() == $this->id) {
+
+                $this->shop->view['oOrder'] = $oOrder;
+
+                $this->shop->render(WPSG_PATH_VIEW.'/mods/mod_amazon/order_view_afterpayment.phtml');
+
+            }
+
+
+        }
 
         public function settings_save()
@@ -98,11 +112,9 @@
         } // public function basket_inner_prebutton(&$basket_view)
 
-        public function setOrderStatus($order_id, $status_id, $inform)
-        {
-
-            $oOrder = wpsg_order::getInstance($order_id);
-
-            if ($oOrder->getPaymentID() == $this->id && in_array($status_id, array(wpsg_ShopController::STATUS_STORNIERT, wpsg_ShopController::STATUS_ZURUECKGEZAHLT)))
-            {
+        public function setOrderStatus($order_id, $status_id, $inform) {
+
+            $oOrder = wpsg_order::getInstance($order_id);
+
+            if ($oOrder->getPaymentID() == $this->id && in_array($status_id, array(wpsg_ShopController::STATUS_STORNIERT, wpsg_ShopController::STATUS_ZURUECKGEZAHLT))) {
 
                 $capture_id = $oOrder->getMeta('amazon_capture_id');
@@ -169,5 +181,8 @@
             if ($oOrder->getToPay() <= 0 || $oOrder->getPaymentID() != $this->id) return;
 
-            if (wpsg_isSizedString($oOrder->getMeta('amazon_order_reference_id')) && !wpsg_isSizedString($oOrder->getMeta('amazon_order_done')))
+            $amazon_order_reference_id = $oOrder->getMeta('amazon_order_reference_id');
+            $amazon_order_done = $oOrder->getMeta('amazon_order_done');
+
+            if (wpsg_isSizedString($amazon_order_reference_id) && !wpsg_isSizedString($amazon_order_done))
             {
 
@@ -198,6 +213,5 @@
                 }
 
-            }
-            else if (wpsg_isSizedString($oOrder->getMeta('amazon_order_done')))
+            } else if (wpsg_isSizedString($amazon_order_done))
             {
 
@@ -207,5 +221,5 @@
             }
 
-            if (wpsg_isSizedString($oOrder->getMeta('amazon_order_reference_id')))
+            if (wpsg_isSizedString($amazon_order_reference_id))
             {
 
@@ -429,23 +443,23 @@
             require_once WPSG_PATH_MOD.'mod_amazon/PayWithAmazon/IpnHandler.php';
 
-            $headers = $_SERVER; // getallheaders();
+            $headers = getallheaders();
             $body = file_get_contents('php://input');
 
-            $ipnHandler = new \PayWithAmazon\IpnHandler($headers, $body);
+            $ipnHandler = new \AmazonPay\IpnHandler($headers, $body);
             $ipnData = $ipnHandler->toArray();
 
-            if (wpsg_isSizedArray($ipnData) && wpsg_isSizedString($ipnData['NotificationType'], 'PaymentCapture'))
-            {
+            if (wpsg_isSizedArray($ipnData) && wpsg_isSizedString($ipnData['NotificationType'], 'PaymentCapture')) {
 
                 $order_id = $ipnData['CaptureDetails']['CaptureReferenceId'];
                 $oOrder = wpsg_order::getInstance($order_id);
 
-                if (wpsg_isSizedInt($this->shop->get_option('wpsg_debugModus'))) $oOrder->log('Amazon:notification:PaymentCapture', print_r($ipnData, 1));
-
-                if ($this->shop->setPayMent($order_id, $ipnData['CaptureDetails']['CaptureAmount']['Amount']) && wpsg_isSizedString($ipnData['CaptureDetails']['CaptureStatus']['State'], 'Completed'))
-                {
+                $oOrder->addLogEntry(
+                    __('Amazon IPN Eingang', 'wpsg'),
+                    print_r($ipnData, true).print_r(getallheaders(), true)
+                );
+
+                if ($this->shop->setPayMent($order_id, $ipnData['CaptureDetails']['CaptureAmount']['Amount']) && wpsg_isSizedString($ipnData['CaptureDetails']['CaptureStatus']['State'], 'Completed')) {
 
                     $oOrder->setMeta('amazon_capture_id', $ipnData['CaptureDetails']['AmazonCaptureId']);
-
                     $this->shop->setOrderStatus($order_id, 100, true);
 
@@ -463,20 +477,17 @@
         } // public function logoutRedirect()
 
-        public function returnRedirect()
-        {
-
-            if (wpsg_isSizedInt($_REQUEST['order_id']) && wpsg_isSizedString($_REQUEST['wpsg_done']))
-            {
+        public function returnRedirect() {
+
+            if (wpsg_isSizedInt($_REQUEST['order_id']) && wpsg_isSizedString($_REQUEST['wpsg_done'])) {
 
                 $_REQUEST['order_id'] = wpsg_sinput("key", $_REQUEST['order_id']);
 
-                if (wpsg_isSizedString($_REQUEST['amazon']['OrderReference']))
-                {
-
-                    $hash = preg_replace('/(\+)|(\=)/', 'A', base64_encode(md5('wpShopGermany'.$_REQUEST['order_id'], $this->shop->get_option("wpsg_salt"))));
-
-                    if ($hash != $_REQUEST['wpsg_done']) die(__('Aufrufsfehler!!', 'wpsg'));
+                if (wpsg_isSizedString($_REQUEST['amazon']['OrderReference'])) {
 
                     $oOrder = wpsg_order::getInstance($_REQUEST['order_id']);
+
+                    $hash = md5($oOrder->__get('secret').$oOrder->getId().$oOrder->__get('secret'));
+                    if (!hash_equals($hash, rawurldecode($_REQUEST['wpsg_done']))) die(__('Aufrufsfehler!!', 'wpsg'));
+
                     $oOrder->setMeta('amazon_order_reference_id', $_REQUEST['amazon']['OrderReference']);
 
@@ -540,5 +551,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->confirmOrderReference(array(
@@ -547,5 +558,5 @@
             ));
 
-            if (wpsg_isSizedInt($this->shop->get_option('wpsg_debugModus'))) $oOrder->log('Amazon:confirmOrderReference', print_r($oResponse->toArray(), 1));
+            if (wpsg_isSizedInt($this->shop->get_option('wpsg_debugMowpdus'))) $oOrder->log('Amazon:confirmOrderReference', print_r($oResponse->toArray(), 1));
 
             return $oResponse->toArray();
@@ -559,5 +570,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->getOrderReferenceDetails(array(
@@ -578,5 +589,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->setOrderReferenceDetails(array(
@@ -601,5 +612,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->authorize(array(
@@ -629,5 +640,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->closeOrderReference(array(
@@ -649,5 +660,5 @@
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->cancelOrderReference(array(
@@ -661,11 +672,10 @@
         } // private function api_cancelPayment($order_id)
 
-        private function api_refund($order_id)
-        {
+        private function api_refund($order_id) {
 
             require_once WPSG_PATH_MOD.'mod_amazon/PayWithAmazon/Client.php';
 
             $oOrder = wpsg_order::getInstance($order_id);
-            $client = new PayWithAmazon\Client($this->getAPIConfig());
+            $client = new AmazonPay\Client($this->getAPIConfig());
 
             $oResponse = $client->refund(array(
@@ -679,6 +689,7 @@
             $arReturn = $oResponse->toArray();
 
-            if (wpsg_isSizedString($arReturn['RefundResult']['RefundDetails']['AmazonRefundId']))
-            {
+            $oOrder->addLogEntry('Amazon Storno', print_r($arReturn, true));
+
+            if (wpsg_isSizedString($arReturn['RefundResult']['RefundDetails']['AmazonRefundId'])) {
 
                 $oOrder->setMeta('amazon_refund_id', $arReturn['RefundResult']['RefundDetails']['AmazonRefundId']);
Index: /mods/wpsg_mod_autodebit.class.php
===================================================================
--- /mods/wpsg_mod_autodebit.class.php	(revision 7755)
+++ /mods/wpsg_mod_autodebit.class.php	(revision 7756)
@@ -475,13 +475,13 @@
 			
 			$iban = str_replace(' ', '', $iban);
-			$iban1 = substr($iban, 4).strval(ord($iban{0}) - 55).strval(ord($iban{1}) - 55). substr($iban, 2, 2);
+			$iban1 = substr($iban, 4).strval(ord($iban[0]) - 55).strval(ord($iban[1]) - 55). substr($iban, 2, 2);
 		
 			for ($i = 0; $i < strlen($iban1); $i++) 
 			{
 				
-				if(ord($iban1{$i}) > 64 && ord($iban1{$i}) < 91) 
+				if(ord($iban1[$i]) > 64 && ord($iban1[$i]) < 91)
 				{
 					
-					$iban1 = substr($iban1, 0, $i).strval(ord($iban1{$i}) - 55).substr($iban1, $i + 1);
+					$iban1 = substr($iban1, 0, $i).strval(ord($iban1[$i]) - 55).substr($iban1, $i + 1);
 					
 				}
Index: /mods/wpsg_mod_crefopay.class.php
===================================================================
--- /mods/wpsg_mod_crefopay.class.php	(revision 7755)
+++ /mods/wpsg_mod_crefopay.class.php	(revision 7756)
@@ -393,7 +393,5 @@
 			if (wpsg_isSizedString($_REQUEST['wpsg_plugin'], 'wpsg_mod_crefopay'))
 			{
-				
-				//mail("daniel@maennchen1.de", "CREFOTEST ".$_REQUEST['return'], print_r($_REQUEST, 1));
-				
+
 				// TemporÃ€r den Request korrigieren
 				// Anfrage URL: http://dev.wpshopgermany.de/warenkorb/?wpsg_plugin=wpsg_mod_crefopay&return=redirect?merchantID=2&...
Index: /mods/wpsg_mod_micropayment_paywindow.class.php
===================================================================
--- /mods/wpsg_mod_micropayment_paywindow.class.php	(revision 7755)
+++ /mods/wpsg_mod_micropayment_paywindow.class.php	(revision 7756)
@@ -85,4 +85,10 @@
 			
 		} // public function __construct()
+
+        public function install() {
+
+            $this->shop->checkDefault('wpsg_mod_micropayment_autorun', '1');
+
+        }
 
 		public function settings_edit() {
Index: /mods/wpsg_mod_willcollect.class.php
===================================================================
--- /mods/wpsg_mod_willcollect.class.php	(revision 7755)
+++ /mods/wpsg_mod_willcollect.class.php	(revision 7756)
@@ -304,3 +304,2 @@
 	} // class wpsg_mod_willcollect extends wpsg_mod_basic
 
-?>
Index: /views/mods/mod_amazon/order_done.phtml
===================================================================
--- /views/mods/mod_amazon/order_done.phtml	(revision 7755)
+++ /views/mods/mod_amazon/order_done.phtml	(revision 7756)
@@ -21,5 +21,5 @@
 <div id="PayWithAmazon" style="<?php echo (($this->view['wpsg_mod_amazon']['state'] === wpsg_mod_amazon::ORDER_DONE_GO)?'display:none':''); ?>"></div>
 
-<script type="text/javascript">/* <![CDATA[ */
+<script type="text/javascript">
  
 	var authRequest; 
@@ -53,6 +53,5 @@
 	var autoRun = setInterval(function(){ 
 
-		if (jQuery('#PayWithAmazon img').length > 0)
-		{
+		if (jQuery('#PayWithAmazon img').length > 0) {
 
 			//setTimeout(function(){ jQuery('#PayWithAmazon img').click(); }, 1000);
@@ -63,5 +62,5 @@
 	}, 100);
 
-/* ]]> */</script>
+</script>
 	
 <?php } ?>
@@ -75,5 +74,5 @@
 	<input type="hidden" name="amazon[OrderReference]" id="wpsg_mod_amazon_OrderReference" value="" />
 	
-	<div id="walletWidgetDiv"></div>
+	<div id="walletWidgetDiv"></div><br />
 	
 	<input type="submit" class="wpsg_button" name="submit" value="<?php echo __('Zahlung durchfÃŒhren', 'wpsg'); ?>" id="wpsg_mod_amazon_doPayment" style="display:none;" />
@@ -82,6 +81,8 @@
 </form>
 
-<script type="text/javascript">/* <![CDATA[ */
-                                            
+<script>
+
+    jQuery('#walletWidgetDiv').show();
+
 	new OffAmazonPayments.Widgets.Wallet( {
 
@@ -118,4 +119,4 @@
 	} ).bind("walletWidgetDiv");
 	    	
-/* ]]> */</script>
+</script>
 <?php } ?>
Index: /views/mods/mod_amazon/order_view_afterpayment.phtml
===================================================================
--- /views/mods/mod_amazon/order_view_afterpayment.phtml	(revision 7756)
+++ /views/mods/mod_amazon/order_view_afterpayment.phtml	(revision 7756)
@@ -0,0 +1,24 @@
+<?php
+
+	/**
+	 * Template fÃŒr die Integration der Amazon Zahlungsart in die Bestellverwaltung
+	 */
+
+	/** @var wpsg_order $oOrder */
+	$oOrder = $this->view['oOrder'];
+
+	$amazon_capture_id = $oOrder->getMeta('amazon_capture_id');
+	$amazon_refund_id = $oOrder->getMeta('amazon_refund_id');
+
+?>
+
+<?php if (wpsg_isSizedString($amazon_refund_id)) { ?>
+
+	<?php echo wpsg_drawForm_Input(false, __('Refund ID', 'wpsg'), $amazon_refund_id, ['readonly' => true]); ?>
+
+<?php } else if (wpsg_isSizedString($amazon_capture_id)) { ?>
+
+	<?php echo wpsg_drawForm_Input(false, __('Capture ID', 'wpsg'), $amazon_capture_id, ['readonly' => true]); ?>
+
+<?php }
+
Index: /views/mods/mod_micropayment_paywindow/settings_edit.phtml
===================================================================
--- /views/mods/mod_micropayment_paywindow/settings_edit.phtml	(revision 7755)
+++ /views/mods/mod_micropayment_paywindow/settings_edit.phtml	(revision 7756)
@@ -14,5 +14,5 @@
 <?php echo wpsg_drawForm_Select('wpsg_mod_micropayment_paywindow_page_error', __('Fehlerseite', 'wpsg'), $view['arPages'], $this->get_option('wpsg_mod_micropayment_paywindow_page_error'), array('help' => 'wpsg_mod_micropayment_paywindow_page_error')); ?>
 <?php echo wpsg_drawForm_Input('wpsg_mod_micropayment_paywindow_paytitle', __('Titel der Zahlung', 'wpsg'), $this->get_option('wpsg_mod_micropayment_paywindow_paytitle'), ['placeholder' => $view['default_pay_title'], 'hint' => __('Maximal 150 Zeichen', 'wpsg')]); ?>
-<?php echo wpsg_drawForm_Input('wpsg_mod_micropayment_paywindow_paytext', __('Titel der Zahlung', 'wpsg'), $this->get_option('wpsg_mod_micropayment_paywindow_paytext'), ['placeholder' => $view['default_pay_text'], 'hint' => __('Maximal 250 Zeichen', 'wpsg')]); ?>
+<?php echo wpsg_drawForm_Input('wpsg_mod_micropayment_paywindow_paytext', __('Text der Zahlung', 'wpsg'), $this->get_option('wpsg_mod_micropayment_paywindow_paytext'), ['placeholder' => $view['default_pay_text'], 'hint' => __('Maximal 250 Zeichen', 'wpsg')]); ?>
 <?php echo wpsg_drawForm_Checkbox('wpsg_mod_micropayment_paywindow_sandbox', __('Testmodus', 'wpsg'), $this->get_option('wpsg_mod_micropayment_paywindow_sandbox')); ?>
 <?php echo wpsg_drawForm_Checkbox('wpsg_mod_micropayment_autorun', __('Zahlung sofort starten', 'wpsg'), $this->get_option('wpsg_mod_micropayment_autorun')); ?>
Index: /views/warenkorb/checkout2.phtml
===================================================================
--- /views/warenkorb/checkout2.phtml	(revision 7755)
+++ /views/warenkorb/checkout2.phtml	(revision 7756)
@@ -50,4 +50,6 @@
 		
 		</div>
+
+        <br /><br />
 						 
 		<?php if ($this->callMods('checkout_handlePayment') === true) { ?>
Index: /views/warenkorb/index.phtml
===================================================================
--- /views/warenkorb/index.phtml	(revision 7755)
+++ /views/warenkorb/index.phtml	(revision 7756)
@@ -79,6 +79,9 @@
 			<?php } ?>
 		</span>
-			
+
+        <?php if (get_the_ID() !== intval($this->get_option('wpsg_page_basket'))) { ?>>
 		<input type="button" class="wpsg_button wpshopgermany_linktokasse" onclick="location.href='<?php echo $this->getURL(wpsg_ShopController:: URL_BASKET); ?>';" value="<?php echo __("Zum Warenkorb", "wpsg"); ?>" />
+        <?php } ?>
+
 	<?php } else { ?>
 		<?php echo __("Keine Artikel im Warenkorb", "wpsg"); ?><br />
@@ -97,5 +100,5 @@
 		<?php if ($this->hasMod('wpsg_mod_request') == '1') { ?>
 			<?php if ($this->view['widget_settings']['wpsg_requestpage'] == 1) { ?>
-				<li class="page_item"><a href="<?php echo $this->getURL(wpsg_ShopController::URL_REQUEST); ?>"><?php echo get_the_title($this->get_option('wpsg_page_request')); ?></a></li>
+				<li class="page_item"><a href="<?php echo $this->f(wpsg_ShopController::URL_REQUEST); ?>"><?php echo get_the_title($this->get_option('wpsg_page_request')); ?></a></li>
 			<?php } ?>
 		<?php } ?>
