One-click

HiPay One click page

The 1-Click is the technique allowing customers to make purchases with payment information already registered to complete their purchase faster.

The purpose of this documentation is to explain the implementation of the one-click feature with HiPay SDKs by giving the possibility to force the CVC of a card or add a new one in your payment page.

In this demonstration, we use a front-end written in HTML/CSS with Javascript (jQuery) and backend server written in PHP. All examples written in this document are for reference only, you should not implement them in production.

User Experience

The screenshot is a payment page of an order of two items for a total amount of €6.75. The user has to choose one of their first two saved cards or to add a new card. The first two cards were previously tokenized during a payment of the same customer.

To use these credit cards, it is mandatory to provide the CVC.

Card displaying

Each card is composed of an input radio button that includes token in its attributes. The associated credit card logo is displayed with the name of the cardholder and the masked PAN with its expiry date

The first registered card 4111**111 can only be used if the user enters the CVC associated with their card, the payment button is disabled if the CVC is not filled.

HiPay SDK JS One-click card
HiPay One click card

This HTML code below corresponds to the above screenshot. A hidden div markup named status-cvc-container contains a check image with its span markup to indicated the cvc is updated.

The div markup named check-cvc-container is displayed by default when the users click one the card. It contains an input to entered the CVC and an OK button.

The PAY button is disabled until the user provides the CVC of the card. If the user sends its CVC by clicking the OK button, the payment information token and payment_product are sent to your server with AJAX call when the PAY button is clicked. After that, check-cvc-container is hidden and status-cvc-container is displayed.

New card

The customer has the option to add a new card if needed. This forms in the exampled is generated with the Hostedfields feature presents in the HiPay JS SDK.

HiPay add new card

Front-End

Card tokenization

When we have tokenized cards, the multi_use parameter was sent with the true value, so this card could be reused for a future payment. Card tokens are written directly into HTML tags of the page.

<div class="payment">
    <div class="card-container" id="card-container-1">
        <div class="bank-card">
            <input class="radio-card" type="radio" name="card" value="card1" id="card1" onclick="manageCardForm(0)"
                data-token-card1="8dd9cf661de7a36c779746ebc35bf3a9" checked>
            <label class="card-label" for="card1">
                <div class="newLabel">
                    <img class="card-logo" src="visa_logo.png">
                    <div class="card-info">
                        <span class="cardholder">John DOE</span>
                        <span class="card-number">4111*********111 - 12/2020</span>
                    </div>
                    <div class="status-cvc-container" style="display:none">
                        <i class="material-icons green-text">check_circle_outline</i>
                        <span class="cvc-updated-label">CVC Updated</span>
                    </div>
                </div>
            </label>
        </div>
        <div class="check-cvc-container" style="display:none">
            <div class="input-cvc">
                <input class="check-cvc" id="cvc-input-1" type="text" placeholder="CVC" maxlength="3">
            </div>
            <button class="btn" type="button" name="button" id="ok-button-1" disabled><span>OK</span></button>
        </div>
      </div>

      <div class="bank-card-new-container">
          <div class="bank-card-new">
              <input class="radio-card with-gap" type="radio" name="card" value="new-card" id="newCard"
                  onclick="manageCardForm(3)">
              <label class="card-label" for="newCard">
                  <div class="newLabel">
                      Nouvelle carte
                  </div>
              </label>
          </div>
          <div id="new-card-form"></div>
      </div>
</div>

To use HiPay Javascript SDK, you have to create an HiPay object named hipayInstance in this example. Then you have to create card instance joined by the selector parameter to the new-card-form div with template set to auto.

hipayInstance = HiPay({
    username: CREDENTIALS_PUBLIC_USERNAME,
    password: CREDENTIALS_PUBLIC_PASSWORD,
    environment: "production",
    lang: "en"
  });

  var config = {
    selector: 'new-card-form',
    template: 'auto',
  };

  cardInstance = hipayInstance.create('card', config);
});

Then, we add a click event on the OK button. We retrieve card token and its cvc entered by the user.

We use the updateToken function provided by HiPay SDK to update the new cvc with the associated token. At the callback success, we set true value in an item in session storage. With the value stored in Session Storage, the user does not have to update his token even he refresh the tab.

The Token can be not updated in the HTML page because it remains the same even after the update. After that, Do not forget to display the status-cvc-container div markup and hide the check-cvc-container div markup.

You can add to the user an error status to prevent

document.getElementById("ok-button-1").addEventListener("click", function() {
  var card1 = document.getElementById("card1");
  var token = card1.getAttribute("data-token-card1");
  var cvc = document.getElementById('cvc-input-1').value;

  var params = {
    request_id: 0,
    card_token: token,
    card_expiry_month: "11",
    card_expiry_year: "2022",
    card_holder: "John Doe",
    cvc: cvc,
  };

  hipayInstance.updateToken(params).then(
    function(response) {
      sessionStorage.setItem("card_cvc_updated", true);
    },
    function(error) {
      // Display a error status
      console.log(error);
    }
  );
});

You can add a keyup event on the CVC input to force users entered 3 (VISA / Mastercard) or 4 (AMEX) digits for the validating. For that, we add a Regex and a maximum length retrieved from its maxlength attribute of the input to enabled or disabled the OK button.

$("#cvc-input-1").keyup(function() {
  var cvc = $("#cvc-input-1").val();
  var maxLength = $("#cvc-input-1").attr("maxlength");
  var okButtonEnabled = (cvc.length == maxLength && /^\d+$/.test(cvc));
  $("#ok-button-1").prop("disabled", !okButtonEnabled);
})

Send payment data to the server

In the first step, we have created the front-end checkout with our two cards and the forced CVC. Now, for sending payment data, we use AJAX call when the user clicked on the pay button.

$("#checkout-button").click(function() {
  //Get the selected card
  var cardSelected = document.querySelector('input[name="card"]:checked').value;

  //Display a progress bar
  $("#hipay-progress").show();
  //Disabled the pay button when processing
  $("#checkout-button").disabled = true;

  var paymentData = {};
  if (cardSelected === 'card1') {
    var token = $("card1").getAttribute("data-token-card1");
    paymentData = {"token": token, "payment_product": "visa"};
  }
  //... Other cards


  //Send payment data in JSON format to your server with an AJAX call
  $.ajax({
    url : "https://your-backend-url/,
    type : 'POST',
    data: JSON.stringify(paymentData),
    contentType: "application/json; charset=utf-8",
    dataType : 'json',
    success : function(result){
      //Hide the progress bar
      $("#hipay-progress").hide();
      //Save the transaction response (transaction_number, order_id and foward_url)
      sessionStorage.setItem("response_order", JSON.stringify(result));
      //Load the forward url
      window.location = result.forward_url;
    }
  });
}

Back-End

This provided code is used in the back-end server. In this example code, we create a HiPay transaction with all required data. We send the request order with the PHP HiPay SDK, and we create a JSON response sent to the front-end.

$logins = [
    "login" => $credentials['private']['login'],
    "password" => $credentials['private']['password'],
  ];

  $data = [
    "orderid"=>"POC_ONE_CLICK_".rand(),
    "operation"=>"Sale",
    "eci"=>7,
    "multi_use"=>1,
    "accept_url"=>$FRONDEND_URL."/?type=accept",
    "decline_url"=>$FRONDEND_URL."/?type=error",
    "cancel_url"=>$FRONDEND_URL."/?type=error",
    "language"=>"fr_FR",
    "email"=>"[email protected]",
    "custom_data"=>"{\"item 1\":\"Large Mocha Latte\", \"item 2\":\"Banana Nut Muffin\"}",
    "time_limit_to_pay"=>90
    // ...
  ];

  try {
    //Get JSON data from front-end
    $receivedData = json_decode(file_get_contents('php://input'),true);

    //Set reponse code  at 200
    http_response_code(200);

    $config = new \HiPay\Fullservice\HTTP\Configuration\Configuration($logins['login'], $logins['password']);
    $clientProvider = new \HiPay\Fullservice\HTTP\SimpleHTTPClient($config);
    $gatewayClient = new \HiPay\Fullservice\Gateway\Client\GatewayClient($clientProvider);

    //Instantiate order request
    $orderRequest = new \HiPay\Fullservice\Gateway\Request\Order\OrderRequest();
    $orderRequest->orderid = $data["orderid"];
    $orderRequest->operation = $data["operation"];
    $orderRequest->description = $data["description"];
    $orderRequest->long_description = $data["long_description"];
    $orderRequest->accept_url = $data["accept_url"];
    $orderRequest->decline_url = $data["decline_url"];
    $orderRequest->pending_url = $data["pending_url"];
    $orderRequest->exception_url = $data["exception_url"];
    $orderRequest->cancel_url = $data["cancel_url"];
    $orderRequest->notify_url = $data["notify_url"];
    $orderRequest->language = $data["language"];
    $orderRequest->cdata1 = $data["cdata1"];
    $orderRequest->custom_data = $data["custom_data"];
    $orderRequest->payment_product = $receivedData['payment_product'];


    $orderRequest->paymentMethod = new \HiPay\Fullservice\Gateway\Request\PaymentMethod\CardTokenPaymentMethod();
    $orderRequest->paymentMethod->eci = $receivedData["eci"];
    $orderRequest->paymentMethod->authentication_indicator = $data["authentication_indicator"];
    $orderRequest->paymentMethod->cardtoken = $receivedData['token'];

    $orderRequest->customerBillingInfo = new \HiPay\Fullservice\Gateway\Request\Info\CustomerBillingInfoRequest();
    $orderRequest->customerBillingInfo->email = $data["email"];
    $orderRequest->customerBillingInfo->phone = $data["phone"];
    $orderRequest->customerBillingInfo->birthdate = $data["birthdate"];
    $orderRequest->customerBillingInfo->gender = $data["gender"];
    $orderRequest->customerBillingInfo->firstname = $data["firstname"];
    $orderRequest->customerBillingInfo->lastname = $data["lastname"];
    $orderRequest->customerBillingInfo->country = $data["country"];
    $orderRequest->customerBillingInfo->recipientinfo = $data["recipientinfo"];
    $orderRequest->customerBillingInfo->streetaddress = $data["streetaddress"];
    $orderRequest->customerBillingInfo->streetaddress2 = $data["streetaddress2"];
    $orderRequest->customerBillingInfo->city = $data["city"];
    $orderRequest->customerBillingInfo->state = $data["state"];
    $orderRequest->customerBillingInfo->zipcode = $data["zipcode"];

    //Send the request order
    $transaction = $gatewayClient->requestNewOrder($orderRequest);

    $response = [
      "transaction_number" => $transaction->getTransactionReference(),
      "order_id" => $transaction->getOrder()->getId(),
      "forward_url" => (!$transaction->getReason() ? $data['accept_url'] : $data['cancel_url']),
    ];

    // This response is send to the front-end at the success of AJAX call
    echo json_encode($response);

  } catch (\Exception $e) {
    $response = [
      "error_message" => $e->getMessage(),
    ];

    // This response is send to the front-end at the failure of AJAX call
    echo json_encode($response);
  }

Transaction Status

The server sent the response the forward URL of the transaction in the AJAX call, with the transaction number and the order ID. The windows.location function will redirect the customer to the final page. If we have a success page, the url will be https://FRONDEND_URL/?type=accept and https://FRONDEND_URL/?type=accept if failure.