Authorize.Net hosted form payment gateway integration with Spring Boot



#Introduction:

Payment gateway is one of most common need now days to process payments in the all the eCommerce and other applications accepting online payments.

There are several payment gateways available worldwide i.e. PayPal, CCAvenue, Stripe etc. Generally all the payment gateways provides SDK/API for almost all the common programming languages i.e. Java, NodeJS, Python, PHP, Ruby etc

Authorize.Net is another popular widely used payment gateway. In this article we will learn how to integrate Authorize.Net payment gateway with any Java based application.

Generally there are two possible ways to implement any payment gateway with your application.

  1. Create your own payment form to accept payment and use Payment Gateway provider’s SDK/API to process the payment.
  2. Or Use Payment Gateway provider’s payment form to process the payment. This approach is known as Hosted from approach.

The hosted form approach is most widely used because it’s secure and full fills all the requirement of PCI DSS compliance.

Click here for Demo.

#Prerequisites:

Before we start, make sure you have the following development environment.

  1. Authorize.Net developers sandbox account.
  2. JDK 1.8 or above
  3. Apache Maven 3.xxx
  4. IDE - STS (Spring Tool Suite preferred)

#Application Overview:

There are three main entities involve in this application

  1. Client application that submits payment amount.

  2. Java backend application (developed in spring boot framework) to configure & request for hosted form.

  3. Authorize.Net server to generate hosted form and process payment

#Steps to create the application:

Let’s divide the application development in following 4 major steps:

  1. Register for Authorize.Net sandbox account & generate API Login key & API Transaction Key
  2. Create spring boot backend application, connect to Authorize.Net using Java SDK & create hosted form request.
  3. Create a client application using HTML5, Bootstrap 4 & JQuery to submit the payment amount.
  4. And complete payment with the hosted form generated by Authorize.Net

#Step 1: Obtain Authorize.Net sandbox account API Login key & API Transaction Key

If you don’t have Authorize.Net sandbox account, go to Authorize.Net sandbox registration page and create a new account.

On successful signup you will get API Login ID & Transaction Key as following

If you already have Authorize.Net sandbox account, Login to your account, go to Account->Settings->API Credentials & Keys & get your API Login key & Transaction Key

#Step 2: Initialize spring boot project, integrate Authorize.Net SDK and create hosted form request

Go to https://start.spring.io/ & setup the maven project. Add following maven dependencies

  1. Web — Full-stack web development with Tomcat and Spring MVC.

  2. Lombok - Java library tool that is used minimize boilerplate code and save development time

    Generate, download, and import project to Spring Tool Suite (STS) IDE.

    Open pom.xml and add following Authorize.Net maven dependency:

Configure a API Login key & Transaction key in application.properties file

#AuthorizeNet payment gateway info
authorizenet.loginid=<your login api key here>
authorizenet.transactionkey=<your transaction key here>

Create HostedFormController.java controller to create hosted form request

@RestController
@RequestMapping("/api/payment")
public class HostedFormController {

	@Value("${authorizenet.loginid}")
	private String apiLoginId;

	@Value("${authorizenet.transactionkey}")
	private String apiTransactionKey;

	@PostMapping(value = "/token")
	public ResponseEntity<Object> generateAPIToken(@RequestBody PaymentAmount paymentAmount)
            throws JsonProcessingException {

        Map<String, Object> responseMap = new LinkedHashMap<String, Object>();
        Double amount = paymentAmount.getAmount();

        ApiOperationBase.setEnvironment(Environment.SANDBOX);

        MerchantAuthenticationType merchantAuthenticationType = new MerchantAuthenticationType();
        merchantAuthenticationType.setName(apiLoginId);
        merchantAuthenticationType.setTransactionKey(apiTransactionKey);
        ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);

        // Create the payment transaction request
        TransactionRequestType txnRequest = new TransactionRequestType();
        txnRequest.setTransactionType(TransactionTypeEnum.AUTH_CAPTURE_TRANSACTION.value());
        txnRequest.setAmount(new BigDecimal(amount).setScale(2, RoundingMode.CEILING));

        SettingType setting = new SettingType();

        setting.setSettingName("hostedPaymentReturnOptions");
        setting.setSettingValue(
                "{\"showReceipt\": true, \"url\": \"https://bhupeshpadiyar.com/poc/authnet/success.html\", \"urlText\": \"Continue\", \"cancelUrl\": \"https://bhupeshpadiyar.com/poc/authnet/error.html\", \"cancelUrlText\": \"Cancel\"}");

        SettingType setting1 = new SettingType();

        setting1.setSettingName("hostedPaymentButtonOptions");
        setting1.setSettingValue("{\"text\": \"Pay\"}");

        SettingType setting2 = new SettingType();
        setting2.setSettingName("hostedPaymentOrderOptions");
        setting2.setSettingValue("{\"show\": false}");

        SettingType setting3 = new SettingType();
        setting3.setSettingName("hostedPaymentStyleOptions");
        setting3.setSettingValue("{\"bgColor\": \"blue\"}");

        SettingType setting4 = new SettingType();
        setting4.setSettingName("hostedPaymentPaymentOptions");
        setting4.setSettingValue("{\"cardCodeRequired\": false, \"showCreditCard\": true, \"showBankAccount\": true}");

        SettingType setting5 = new SettingType();
        setting5.setSettingName("hostedPaymentSecurityOptions");
        setting5.setSettingValue("{\"captcha\": true}");

        SettingType setting6 = new SettingType();
        setting6.setSettingName("hostedPaymentShippingAddressOptions");
        setting6.setSettingValue("{\"show\": true, \"required\": true}");

        SettingType setting7 = new SettingType();
        setting7.setSettingName("hostedPaymentBillingAddressOptions");
        setting7.setSettingValue("{\"show\": true, \"required\": true}");

        SettingType setting8 = new SettingType();
        setting8.setSettingName("hostedPaymentCustomerOptions");
        setting8.setSettingValue("{\"showEmail\": true, \"requiredEmail\": true, \"addPaymentProfile\": true}");

        SettingType setting9 = new SettingType();
        setting9.setSettingName("hostedPaymentOrderOptions");
        setting9.setSettingValue("{\"show\": true, \"merchantName\": \"BhupeshPadiyar.Com Inc.\"}");

        SettingType setting10 = new SettingType();
        setting10.setSettingName("hostedPaymentIFrameCommunicatorUrl");
        setting10.setSettingValue("{\"url\": \"https://bhupeshpadiyar.com/\"}");

        ArrayOfSetting alist = new ArrayOfSetting();
        alist.getSetting().add(setting);
        alist.getSetting().add(setting1);
        alist.getSetting().add(setting3);

        alist.getSetting().add(setting4);
        alist.getSetting().add(setting5);
        alist.getSetting().add(setting6);

        alist.getSetting().add(setting7);
        alist.getSetting().add(setting8);
        alist.getSetting().add(setting9);
        alist.getSetting().add(setting10);

        GetHostedPaymentPageRequest apiRequest = new GetHostedPaymentPageRequest();
        apiRequest.setTransactionRequest(txnRequest);
        apiRequest.setHostedPaymentSettings(alist);

        GetHostedPaymentPageController controller = new GetHostedPaymentPageController(apiRequest);
        controller.execute();

        GetHostedPaymentPageResponse response = new GetHostedPaymentPageResponse();
        response = controller.getApiResponse();

        if (response != null) {

            if (response.getMessages().getResultCode() == MessageTypeEnum.OK) {

                responseMap.put("status", 200);
                responseMap.put("token", response.getToken());
                responseMap.put("message", response.getMessages());

            } else {
                responseMap.put("status", 201);
                responseMap.put("message", response.getMessages());

            }
        }

        return new ResponseEntity<>(responseMap, HttpStatus.OK);
	}

}

There are several setting parameters in this hosted form request configuration lets discuss about few important parameters

  • hostedPaymentReturnOptions : Use these options to control the receipt page, return URLs, and buttons for both the payment form and the receipt page.
{"showReceipt": true, "url": "https://bhupeshpadiyar.com/poc/authnet/success.html", "urlText": "Continue", "cancelUrl": "https://bhupeshpadiyar.com/poc/authnet/error.html", "cancelUrlText": "Cancel"}
  • hostedPaymentPaymentOptions : Use to control which payment options to display on the hosted payment form.

    By default, cardCodeRequired and customerProfileId are false, and showCreditCard and showBankAccount are true.

    {“cardCodeRequired”: false, “showCreditCard”: true, “showBankAccount”: true, “customerProfileId”: false}

  • hostedPaymentShippingAddressOptions : Use show to enable or disable the shipping address on the form. Use required to require the shipping address. Both show and required default to false.
{"show": false, "required": false}
  • hostedPaymentBillingAddressOptions : Use show to enable or disable the billing address on the form. Defaults to true. Use required to require the billing address. Defaults to false.
{"show": false, "required": false}

Run the spring boot application and test the RESTFull API to create hosted form request

API URL : http://localhost:8080/api/payment/token

Type: POST

Request Body:

{
	"amount": 20.00
}

Response:

"status": 200,
    "token": <Generated Token>,
    "message": {
        "resultCode": "OK",
        "message": [
            {
                "code": "I00001",
                "text": "Successful."
            }
        ]
    }

#Step 3: Create a HTML form to submit payment amount & call hosted form RESTFull API using AJAX

Our hosted form creation RESTFull API is ready. Now let’s create an UI form to submit payment amount & and submit the form to create hosted form.

Following are the detailed steps

  • Create a simple HTML payment form with an amount field and payment button

    Submit payment amount form

    <form method="post" class="form" role="form" autocomplete="off">
       <div class="form-group row">
          <label class="col-md-12">Payment Amount</label>
          <div class="form-inline col-md-12">
             <div class="input-group col-md-12">
                <div class="input-group-prepend">
                   <span class="input-group-text">$</span>
                </div>
                <input type="number" pattern="/^-?\d+.?\d*$/"  onKeyPress="if(this.value.length==8) return false;" class="form-control text-right" id="amount" placeholder="0.00">
             </div>
          </div>
       </div>
       <hr class="my-5">
       <div class="form-group row">
          <div class="col-md-12">
             <button type="button" id="proceedPayment"  class="btn btn-success btn-md btn-block">
             Proceed Payment
             </button>
          </div>
       </div>
    </form>
    

Redirect to Authorize.Net hosted form

<form method="post"  id="authNetHostedForm" name="authNetHostedForm" action="https://test.authorize.net/payment/payment">
      <input type="hidden" name="token" id="token" />
       <button id="btnContinuePayment" onclick=""  class="d-none btn btn-success btn-md btn-block">Proceed Payment</button>
</form>
  • On click payment amount button call hosted form RESTFull API using AJAX & get the id token.

  • On success response from hosted form RESTFull API, set the id token to hidden text field inside process payment form and submit the process payment form. It will redirect to hosted form page.

AJAX request and redirect to hosted form

$("#submitPaymentAmount").click(function(event) {
var postData = JSON.stringify({amount:$("#amount").val()});
var paymentUrl =  "http://localhost:8080/api/payment/token"
              showLoader(event);
               
               $.ajax({
                   type:"POST",
                   url:paymentUrl,
                   data:postData,
                   async:true,
                   contentType: "application/json",
                   success: function (data) {
                       if(data.status == 200) {
                          $("#paymentForm").removeClass("d-none");
                          $("#submitPaymentButton").addClass("d-none");
                          $("#token").val(data.token);
                          $("#btnContinuePayment").click();
                       } else{
                         hideLoader(event);
                       }
                   },
                   error: function(error){
                     hideLoader(event);
                   }
               });
        });

Complete HTML form & AJAX code

<!DOCTYPE html>
<html lang="en" dir="ltr">
   <head>
      <meta charset="utf-8">
      <title>AuthorizeNet : Hosted form payment gateway example </title>
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
         integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
   </head>
   <body>
      <div class="col-md-4 offset-md-4">
      <span class="anchor" id="formPayment"></span>
      <hr class="my-5">
      <div class="card card-outline-secondary">
         <div class="card-body">
            <h3 class="text-center">AuthorizeNet : Hosted Payment Gateway</h3>
            <hr class="my-3">
            <form method="post" id="submitPaymentAmountForm" class="form" role="form" autocomplete="off">
               <div class="form-group row">
                  <label class="col-md-12">Payment Amount</label>
                  <div class="form-inline col-md-12">
                     <div class="input-group col-md-12">
                        <div class="input-group-prepend">
                           <span class="input-group-text">$</span>
                        </div>
                        <input type="number" pattern="/^-?\d+\.?\d*$/"  onKeyPress="if(this.value.length==8) return false;" class="form-control text-right" id="amount" placeholder="0.00">
                     </div>
                  </div>
               </div>
               <hr class="my-5">
               <div class="form-group row">
                  <div class="col-md-12">
                     <button type="button" id="submitPaymentAmount"  class="btn btn-success btn-md btn-block">
                     Proceed Payment
                     </button>
                  </div>
               </div>
            </form>
            <form method="post"  id="processPaymentForm" name="processPaymentForm" action="https://test.authorize.net/payment/payment">
               <input type="hidden" name="token" id="token" />
               <button id="btnContinuePayment" onclick=""  class="d-none btn btn-success btn-md btn-block">Proceed Payment</button>
            </form>
         </div>
      </div>
      <p class="copyright" style="text-align:center;padding:40px 0;">
         Developed by
         <a target="_blank" href="https://www.bhupeshpadiyar.com">Bhupesh Singh Padiyar</a>
      </p>
   </body>
   <script src="https://code.jquery.com/jquery-3.5.0.min.js"
      integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ="
      crossorigin="anonymous"></script>
   <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
      integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
      crossorigin="anonymous"></script>
   <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
      integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
      crossorigin="anonymous"></script>
   <script type="text/javascript">
      function showLoader(event){
          var id=event.target.id;
      
          var loaderContent = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span><span class="sr-only">Please wait...</span>';
          $("#"+id).empty();
          $("#"+id).attr("disabled", true)
          $("#"+id).append(loaderContent);
      
       }
      
      function hideLoader(event){
        var id=event.target.id;
        var loaderContent = 'Proceed Payment';
        $("#"+id).empty();
        $("#"+id).attr("disabled", false)
        $("#"+id).append(loaderContent);
      }
      
      $( document ).ready(function() {
          var amountVal = $("#amount").val();
          if(amountVal == 0 || amountVal ==''  || amountVal == ' ') {
              $("#proceedPayment").prop('disabled', true);
          }
      
          $('#amount').keyup(function() {
            var amountVal = $("#amount").val();
            if(amountVal !='') {
                $("#proceedPayment").prop('disabled', false);
            } else{
                $("#proceedPayment").prop('disabled', true);
            }
          });
      });
      
      
      $("#submitPaymentAmount").click(function(event) {
      
                 var postData = JSON.stringify({amount:$("#amount").val()});
                 var paymentUrl =  "http://localhost:8080/api/payment/token"
      
                 showLoader(event);
      
                 $.ajax({
                     type:"POST",
                     url:paymentUrl,
                     data:postData,
                     async:true,
                     contentType: "application/json",
                     success: function (data) {
                         //console.log(data);
                         if(data.status == 200) {
                            $("#paymentForm").removeClass("d-none");
                            $("#submitPaymentButton").addClass("d-none");
                            $("#token").val(data.token);
                            $("#btnContinuePayment").click();
                         } else{
                           hideLoader(event);
                         }
                     },
                     error: function(error){
                       //console.log(error);
                       hideLoader(event);
                     }
                 });
          });
      
      
   </script>
</html>

#Payment amount form screenshot

#Step 4: Process payment with hosted form

After successful payment submission the page will be redirected to Authorize.Net hosted payment page. The hosted form looks as following screenshot.

Fill the payment details and billing address and click pay button.

#Hosted payment form screenshot

#Test Card Numbers:

The following test credit card numbers will only work in the sandbox. Use an expiration date after today’s date. If the card code is required, please use any 3-digit combination for Visa, Mastercard, Discover, EnRoute, and JCB; use a 4-digit combination for American Express.

Test Card Brand     Number
American Express     370000000000002
Discover     6011000000000012
JCB     3088000000000017
Visa     4007000000027
    4012888818888
    4111111111111111
Mastercard     5424000000000015
    2223000010309703
    2223000010309711

#Receipt page screenshot:

#Payment confirmation page screenshot:

Click here for Demo.

#References


#Source Code:


You may Download the source code from the following GitHub link


https://github.com/bhupeshpadiyar/authorizenet-hosted-payment

Thank You. Happy Learning!!!