title: MPGS integration 3DSecure PHP
body: <p>I've downloaded the <a href="https://test-gateway.mastercard.com/api/documentation/downloads/index.html?locale=en_US" rel="nofollow noreferrer">Direct Payment</a> Sample_REST-JSON_PHP.zip . I successfully integrated with my merchant info, but when doing the pay operation in <code>x_pay_simple.html</code> I get the following error</p>
  
  <pre><code>{
     "error": {
         "cause": "INVALID_REQUEST",
         "explanation": "Missing parameter. value: null - reason: A 3DS Authentication ID value or 3DS Authentication Details is required for the transaction source used for this transaction",
         "field": "3DSecure",
         "validationType": "MISSING"
     },
     "result": "ERROR"
  }
  </code></pre>
  
  <p>I read the docs and I understood that 3DSecure is generated from the gateway, I think add payment &amp; 3Dsecure are done in 1 use case. </p>
  
  <p>how can I add 3DSecure to my implementation ? </p>
  
  <p>Here's the HTML :</p>
  
  <pre><code>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;&lt;html&gt;
  &lt;link rel="stylesheet" type="text/css" href="./assets/paymentstyle.css" /&gt;
  
  &lt;head&gt;
      &lt;title&gt;API Example Code&lt;/title&gt;
      &lt;meta http-equiv="Content-Type" content="text/html, charset=iso-8859-1"&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
  
      &lt;h1&gt;PHP Example - REST (JSON)&lt;/h1&gt;
      &lt;h3&gt;Simple Pay Operation&lt;/h3&gt;
      &lt;p&gt;&lt;a href="index.html"&gt;Return to the Home Page&lt;/a&gt;&lt;/p&gt;
  
      &lt;form action="./process.php" method="post"&gt;
  
      &lt;table width="60%" align="center" cellpadding="5" border="0"&gt;
  
          &lt;!-- Credit Card Fields --&gt;
          &lt;tr class="title"&gt;
              &lt;td colspan="2" height="25"&gt;&lt;P&gt;&lt;strong&gt;URL Fields&lt;/strong&gt;&lt;/P&gt;&lt;/td&gt;
          &lt;/tr&gt;
  
          &lt;tr&gt;
              &lt;td colspan="2" height="25"&gt;&lt;P class="desc"&gt;Order and Transaction IDs are required and used to calculate the URL along with the version and merchant ID. In your integration, you would calculate these fields within your code (process.php based on this example) and not expose these to the card holder on this page, or pass them as hidden fields.&lt;/P&gt;&lt;/td&gt;
          &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;version &lt;/strong&gt;&lt;/td&gt;
               &lt;td width="50%"&gt;&lt;input type="text" readonly="readonly" name="version" value="34" size="8" maxlength="80" /&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;order.id&lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="orderId" value="" size="20" maxlength="60"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
                &lt;td align="right" width="50%"&gt;&lt;strong&gt;transaction.id&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;input type="text" name="transactionId" value="" size="20" maxlength="60"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
  
  
  
  
           &lt;tr&gt;&lt;td colspan="2"&gt;&lt;/td&gt;&lt;/tr&gt;
  
           &lt;tr class="title"&gt;
               &lt;td colspan="2" height="25"&gt;&lt;P&gt;&lt;strong&gt;&amp;nbsp;Transaction Fields&lt;/strong&gt;&lt;/P&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;method &lt;/strong&gt;&lt;/td&gt;
               &lt;td width="50%"&gt;&lt;input type="text" readonly="readonly" name="method" value="PUT" size="20" maxlength="80"/&gt; ** See Note 1 Below&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;apiOperation &lt;/strong&gt;&lt;/td&gt;
               &lt;td width="50%"&gt;&lt;input type="text" readonly="readonly" name="apiOperation" value="PAY" size="20" maxlength="80"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
  
  
  
          &lt;tr&gt;
              &lt;td align="right"&gt;&lt;strong&gt;sourceOfFunds.type &lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;input type="text" name="sourceOfFunds[type]" value="CARD" size="19" maxlength="80"/&gt;&lt;/td&gt;
          &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
               &lt;td align="right"&gt;&lt;strong&gt;sourceOfFunds.provided.card.number &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="sourceOfFunds[provided][card][number]" value="" size="19" maxlength="80"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td align="right"&gt;&lt;strong&gt;sourceOfFunds.provided.card.expiry.month &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="sourceOfFunds[provided][card][expiry][month]" value="" size="1" maxlength="2"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
               &lt;td align="right"&gt;&lt;strong&gt;sourceOfFunds.provided.card.expiry.year &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="sourceOfFunds[provided][card][expiry][year]" value="" size="1" maxlength="2"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td align="right"&gt;&lt;strong&gt;sourceOfFunds.provided.card.securityCode &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="sourceOfFunds[provided][card][securityCode]" value="" size="8" maxlength="4"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr class="shade"&gt;
               &lt;td align="right"&gt;&lt;strong&gt;order.amount &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="order[amount]" value="" size="8" maxlength="13"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td align="right"&gt;&lt;strong&gt;order.currency &lt;/strong&gt;&lt;/td&gt;
               &lt;td&gt;&lt;input type="text" name="order[currency]" value="SAR" size="8" maxlength="3"/&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td colspan="2"&gt;&lt;center&gt;&lt;input type="submit" name="submit" value="Process Payment"/&gt;&lt;/center&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
           &lt;tr&gt;&lt;td colspan="2"&gt;&lt;/td&gt;&lt;/tr&gt;
  
           &lt;tr&gt;
               &lt;td colspan="2" height="25"&gt;&lt;P class="desc"&gt;&lt;strong&gt;Note 1:&lt;/strong&gt; This field is used by this example to set the HTTP Method for sending the transaction. In your integration, you should determine the HTTP Method in your code (process.php based on this example) and never display it to the card holder or pass it as a hidden field.&lt;/P&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
      &lt;/table&gt;
  
  
      &lt;/form&gt;
      &lt;br/&gt;&lt;br/&gt;
  
  &lt;/body&gt;
  </code></pre>
  
  <p></p>
  
  <p>process.php</p>
  
  <pre><code>&lt;?php
      /* Main controller page
      1. Create 1 MerchantConfiguration object for each merchant ID
      2. Create 1 Parser object
      3. Call Parser object FormRequest method to form the request that will be sent to the payment server
      4. Parse the formed reqest to SendTransaction method to attempt to send the transaction to the payment server
      5. Store the received transaction response in a variable
      6. Include receipt page which will output the response HTML and parse the server response
  
      */
  
      include "configuration.php";
      include "connection.php";
  
  
      // This is used to set the HTTP operation for sending the transaction
      // In your integration, you should never pass this in, but set the value here based on your requirements
      if (array_key_exists("method", $_POST))
        $method = $_POST["method"];
  
  
      // The following section allows the example code to setup the custom/changing components to the URI
      // In your integration, you should never pass these in, but set the values here based on your requirements
      $customUri = "";
      if (array_key_exists("orderId", $_POST))
        $customUri .= "/order/" . $_POST["orderId"];
  
      if (array_key_exists("transactionId", $_POST))
        $customUri .= "/transaction/" . $_POST["transactionId"];
  
  
      // Add any HTML/$_POST field names that you want to unset to this array
      // If you have any other fields in the HTTP POST, you need to process them here and remove from $_POST
      // After this, $_POST should only contain fields that are being sent as part of the transaction
      $unsetNames = array("orderId", "transactionId", "submit", "method");
  
      // loop through each field in the unsetNames array
      // unset the field if the key exists
      foreach ($unsetNames as $fieldName) {
        if (array_key_exists($fieldName, $_POST))
          unset($_POST[$fieldName]);
      }
  
      // Creates the Merchant Object from config. If you are using multiple merchant ID's,
      // you can pass in another configArray each time, instead of using the one from configuration.php
      $merchantObj = new Merchant($configArray);
  
      // The Parser object is used to process the response from the gateway and handle the connections
      $parserObj = new Parser($merchantObj);
  
      // In your integration, you should never pass this in, but store the value in configuration
      // If you wish to use multiple versions, you can set the version as is being done below
      if (array_key_exists("version", $_POST)) {
        $merchantObj-&gt;SetVersion($_POST["version"]);
        unset($_POST["version"]);
      }
  
      // form transaction request
      $request = $parserObj-&gt;ParseRequest($_POST);
  
      // if no post received from HTML page (parseRequest returns "" upon receiving an empty $_POST)
      if ($request == "")
        die();
  
      // print the request pre-send to server if in debug mode
      // this is used for debugging only. This would not be used in your integration, as DEBUG should be set to FALSE
      if ($merchantObj-&gt;GetDebug())
        echo $request . "&lt;br/&gt;&lt;br/&gt;";
  
      // forms the requestUrl and assigns it to the merchantObj gatewayUrl member
      // returns what was assigned to the gatewayUrl member for echoing if in debug mode
      $requestUrl = $parserObj-&gt;FormRequestUrl($merchantObj, $customUri);
  
      // this is used for debugging only. This would not be used in your integration, as DEBUG should be set to FALSE
      if ($merchantObj-&gt;GetDebug())
        echo $requestUrl . "&lt;br/&gt;&lt;br/&gt;";
  
  
      // attempt sending of transaction
      // $response is used in receipt page, do not change variable name
      $response = $parserObj-&gt;SendTransaction($merchantObj, $request, $method);
  
      // print response received from server if in debug mode
      // this is used for debugging only. This would not be used in your integration, as DEBUG should be set to FALSE
      if ($merchantObj-&gt;GetDebug()) {
        // replace the newline chars with html newlines
        $response = str_replace("\n", "&lt;br/&gt;", $response);
        echo $response . "&lt;br/&gt;&lt;br/&gt;";
        die();
      }
  
  
      // the receipt page is included and displayed here.
      // in your integration, you would most likely also want process the transaction response, and make appropriate updates
      // you can see how to parse and retrieve the results and other fields in the transaction at the top of receipt.php
      include "receipt.php";
  
      ?&gt;
  </code></pre>
  
  <p>receipt.php</p>
  
  <pre><code>    &lt;?php
  
  //Rima - start
  include "process.php";
  //Rima - end
  
  
  $errorMessage = "";
  $errorCode = "";
  $gatewayCode = "";
  $result = "";
  
  $tmpArray = array();
  
  // [Snippet] howToDecodeResponse - start
  // $response is defined in process.php as the server response
  $responseArray = json_decode($response, TRUE);
  // [Snippet] howToDecodeResponse - end
  
  // either a HTML error was received
  // or response is a curl error
  if ($responseArray == NULL) {
    print("JSON decode failed. Please review server response (enable debug in config.php).");
    die();
  }
  
  // [Snippet] howToParseResponse - start
  if (array_key_exists("result", $responseArray))
    $result = $responseArray["result"];
  // [Snippet] howToParseResponse - end
  
  // Form error string if error is triggered
  if ($result == "FAIL") {
    if (array_key_exists("reason", $responseArray)) {
      $tmpArray = $responseArray["reason"];
  
      if (array_key_exists("explanation", $tmpArray)) {
        $errorMessage = rawurldecode($tmpArray["explanation"]);
      }
      else if (array_key_exists("supportCode", $tmpArray)) {
        $errorMessage = rawurldecode($tmpArray["supportCode"]);
      }
      else {
        $errorMessage = "Reason unspecified.";
      }
  
      if (array_key_exists("code", $tmpArray)) {
        $errorCode = "Error (" . $tmpArray["code"] . ")";
      }
      else {
        $errorCode = "Error (UNSPECIFIED)";
      }
    }
  }
  
  else {
    if (array_key_exists("response", $responseArray)) {
      $tmpArray = $responseArray["response"];
      if (array_key_exists("gatewayCode", $tmpArray)){
        $gatewayCode = rawurldecode($tmpArray["gatewayCode"]);
  
      }
  
    }
      else
        $gatewayCode = "Response not received.";
    }
  }
  
  ?&gt;
  &lt;!--    The following is a simple HTML page to display the response to the transaction.
        This should never be used in your integration --&gt;
  &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
  &lt;html&gt;
    &lt;link rel="stylesheet" type="text/css" href="assets/paymentstyle.css" /&gt;
      &lt;head&gt;
        &lt;title&gt;API Example Code&lt;/title&gt;
        &lt;meta http-equiv="Content-Type" content="text/html, charset=iso-8859-1"&gt;
      &lt;/head&gt;
      &lt;body&gt;
      &lt;br/&gt;
      &lt;center&gt;&lt;h1&gt;PHP Example - REST (JSON)&lt;/h1&gt;&lt;/center&gt;
      &lt;center&gt;&lt;h3&gt;Receipt Page&lt;/h3&gt;&lt;/center&gt;&lt;br/&gt;&lt;br/&gt;
  
    &lt;table width="60%" align="center" cellpadding="5" border="0"&gt;
  
    &lt;?php
      // echo HTML displaying Error headers if error is found
      if ($errorCode != "" || $errorMessage != "") {
    ?&gt;
        &lt;tr class="title"&gt;
               &lt;td colspan="2" height="25"&gt;&lt;P&gt;&lt;strong&gt;&amp;nbsp;Error Response&lt;/strong&gt;&lt;/P&gt;&lt;/td&gt;
           &lt;/tr&gt;
           &lt;tr&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;&lt;i&gt;&lt;?=$errorCode?&gt;: &lt;/i&gt;&lt;/strong&gt;&lt;/td&gt;
               &lt;td width="50%"&gt;&lt;?=$errorMessage?&gt;&lt;/td&gt;
           &lt;/tr&gt;
    &lt;?php
      }
  
      else {
    ?&gt;
        &lt;tr class="title"&gt;
               &lt;td colspan="2" height="25"&gt;&lt;P&gt;&lt;strong&gt;&amp;nbsp;&lt;?=$gatewayCode?&gt;&lt;/strong&gt;&lt;/P&gt;&lt;/td&gt;
           &lt;/tr&gt;
           &lt;tr&gt;
               &lt;td align="right" width="50%"&gt;&lt;strong&gt;&lt;i&gt;Result: &lt;/i&gt;&lt;/strong&gt;&lt;/td&gt;
               &lt;td width="50%"&gt;&lt;?=$result?&gt;&lt;/td&gt;
           &lt;/tr&gt;
    &lt;?php
       }
    ?&gt;
        &lt;!-- Response Fields --&gt;
  
           &lt;tr class="title"&gt;
               &lt;td colspan="2" height="20"&gt;&lt;P&gt;&lt;strong&gt;&amp;nbsp;JSON Response&lt;/strong&gt;&lt;/P&gt;&lt;/td&gt;
           &lt;/tr&gt;
  
    &lt;/table&gt;
  
    &lt;table width="50%" align="center" cellpadding="5" border="0"&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;p&gt;The display of the below response is intended to be for this example only. In your integration, you should parse this      response to extract and use the response fields required.&lt;/p&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
       &lt;tr&gt;
         &lt;td align="center" width="100%"&gt;
            &lt;textarea rows="40" cols="118" name="outContent" id="outContent"&gt;&lt;?=$response?&gt;&lt;/textarea&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
  
      &lt;!-- The below Java Script &amp; HTML formats the JSON output result to make it clean
           and readable. You should not use these scripts to format or expose the
           JSON response in your integration, but rather store/use any of the
           specific fields required for your integration --&gt;
      &lt;tr&gt;
        &lt;td align="center" width="100%"&gt;
          &lt;p&gt;Note: The above response has been formatted to make it easier to read. The reformatting also changes amounts to be strictly defined JSON numbers. This means 0's are removed from after the decimal place i.e. 1.00 is displayed as 1 and 1.10 is displayed as 1.1. &lt;a href="javascript:displayRawJSON()"&gt;Click here to display the unformatted JSON Response&lt;/a&gt;&lt;/p&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;script type="text/javascript" src="./assets/json2.js"&gt;&lt;/script&gt;
      &lt;script type="text/javascript" src="./assets/jsonformatter.js"&gt;&lt;/script&gt;
      &lt;script type="text/javascript" src="./assets/jquery-1.3.2.js"&gt;&lt;/script&gt;
  
      &lt;script&gt;
        var orginalJSON = $("#outContent").val();
        function FormatTextarea() {
          var sJSON = $("#outContent").val();
          var oJSON = JSON.parse(sJSON);
          sJSON = FormatJSON(oJSON);
          $("#outContent").val(sJSON);
        }
        FormatTextarea();
  
        function displayRawJSON() {
          $("#outContent").val(orginalJSON);
        }
      &lt;/script&gt;
  
     &lt;/table&gt;
  
    &lt;br/&gt;&lt;br/&gt;
     &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>