Native Checkout v1.0

With Native Checkout v1.0 you can power custom products and give them the ability to receive payments. Its advantage is that the customer never leaves your website/checkout flow or branding. Using Native Checkout requires programming experience, but anyone with previous exposure to API integration should find it easy to use.

Native Checkout v1.0 is to be deprecated in the near future. Please refer to Native Checkout v2.0 (3DS) for a more updated approach.

Before you begin:

Integrating with Native Checkout v1.0 now consists of the following steps:

Step 1: Build a custom payment form

The following is an example of a typical payment form that you can easily build with an HTML editor. Decorate your HTML form with data-vp attributes.

<form action="" method="POST" id="payment-form">
	<div class="form-row">
	<label>
		<span>Cardholder Name</span>
		<input type="text" size="20" name="txtCardHolder" autocomplete="off" data-vp="cardholder"/>
	</label>
	</div>

	<div class="form-row">
	<label>
		<span>Card Number</span>
		<input type="text" size="20" name="txtCardNumber" autocomplete="off" data-vp="cardnumber"/>
	</label>
	</div>

	<div class="form-row">
	<label>
		<span>CVV</span>
		<input type="text" name="txtCVV" size="4" autocomplete="off" data-vp="cvv"/>
	</label>
	</div>

	<div class="form-row">
	<label>
		<span>Expiration (MM/YYYY)</span>
		<input type="text" size="2" name="txtMonth" autocomplete="off" data-vp="month"/>
	</label>
	<span> / </span>
	<input type="text" size="4" name="txtYear" autocomplete="off" data-vp="year"/>
	</div>

	<div class="form-row">
		<label>
			<span>Installments</span>
			<select id="drpInstallments" name="drpInstallments" style="display:none"></select>
		</label>
	</div>

	<input type="hidden" name="OrderId" value="146228" /> <!--Custom Field-->
	<input type="hidden" id="hidToken" name="hidToken" /> <!--Hidden Field to hold the Generated Token-->
	<input type="button" id="submit" value="Submit Payment" />
</form>

The name attribute of the HTML element is used to remove all the sensitive card details (number, expiration month, expiration year and CVV) before the submission of the form, limiting your PCI Scope.

By doing this, we ensure that no sensitive cardholder data is processed or stored by the merchant, removing completely the need for complex PCI-DSS Compliance implementation on your part.

If you omit any of the above mentioned fields, the Native Checkout process will fail to complete and you’ll receive an error.

The data-vp attribute instructs Viva Payments to encrypt and securely transmit card data to our servers and return a special single-use token, which you can use for completing the payment.

Make sure to omit the data-vp attribute for your custom fields. The field orderId in the example above demonstrates this use.

The select field drpInstallments makes use of the Installments functionality that is described later on.

Step 2: Add jQuery to your website

Include jQuery in the <head> section of your website.

<script type="text/javascript" src="/scripts/jQuery/jquery-latest.min.js"></script>

We recommend you always use the latest stable available version of jQuery, which maximises browser and platform compatibility.

Avoid referencing jQuery directly from an online third-party source. It’s bad practice, security wise, and may yield complicated and unpredicted problems in the future. It’s always best to download the latest stable minified jQuery version and host it on your site.

If you do choose to use an online reference, ensure it’s securely hosted (over https not http) otherwise your client’s browser will flag security alerts.

Step 3: Add script to your website

Include the Native Checkout script in the <head> section of your website

<script type="text/javascript" src="https://www.vivapayments.com/web/checkout/js"></script>

Step 4: Initialize

Initialize the process by calling the cards.setup() method once the document is fully loaded (e.g. on $(document).ready()).

<script type="text/javascript">
$(document).ready(function (){
       VivaPayments.cards.setup({
        	publicKey: 'ujYKFkdV15qW9xFn0BDIuiqCHnejspL5GLnxr4QK484=',
        	baseURL: 'https://demo.vivapayments.com',
        	cardTokenHandler: function (response) {
            		if (!response.Error) {
            			$('#hidToken').val(response.Token);
            			$('#payment-form').submit();
            		}
            		else
            			alert(response.Error);
        	},
        	installmentsHandler: function (response) {
            		if (!response.Error) {
            	       		if (response.MaxInstallments == 0)
            	       			return;
            	       		$('#drpInstallments').show();
            	       		for(i=1; i<=response.MaxInstallments; i++){
            	       			$('#drpInstallments').append($("<option>").val(i).text(i));
            	       		}
            		}
            		else
            			alert(response.Error);
        	}
       });
});
</script>

Use the public key you obtained previously and set it as publicKey property in your HTML. Use the baseURL property (optional) to target either demo or production environment. If omitted, production environment is assumed.

Native Checkout fires two events:

  • Token Creation event (your handler is set in property cardTokenHandler), which gives you the generated token. The example above, sets the generated token in the hidden field token and then submits the form.

  • Installments check event (optional, your handler is set in property installmentsHandler), which fires each time a user types his credit card and a check for supported installments is carried out. Response contains the maximum allowed installments for the user’s card. The example above uses the MaxInstallments property to set the values of a dropdown drpInstallments.

Step 5: Add a button to your form that requests a token

The button should not submit the form, but call the requestToken() method instead. You can handle the form submission in the cardTokenHandler.

<input type="button" id="submit" value="Submit" onclick="VivaPayments.cards.requestToken();" />

Step 6: Call the API to securely process the payment

By now you should have received the form server side, with the generated token along and the additional clear text fields you added to the form. All you need to do now is call Viva Payments’ API to create an Order and charge the card by passing the token, amount and a secure approved source. If you choose to enable instalments, you can pass the user selected instalments count to the charge card.

Full code sample

The server-side part of your checkout page should receive the above fields and post to Viva Payments’s API the encrypted data as follows (example in asp.net c# webforms)

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" EnableEventValidation="false"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.7.1.min.js"></script>
    <script type="text/javascript" src="https://demo.vivapayments.com/web/checkout/js"></script>
</head>
<body>
    <form id="paymentform" runat="server">
        CardHolder's name:
        <asp:TextBox ID="txtCardHolder" runat="server" data-vp="cardholder" Text="test"></asp:TextBox><br />
        CardNumber:
        <asp:TextBox ID="txtCardNumber" runat="server" data-vp="cardnumber" MaxLength="16"></asp:TextBox><br />
        <div id="divInstallments" style="display:none">
            Installments: <asp:DropDownList ID="drpInstallments" runat="server"></asp:DropDownList>
        </div>
        CVV:
        <asp:TextBox ID="txtCVV" runat="server" data-vp="cvv"></asp:TextBox><br />
        Expiration Month:
        <asp:TextBox ID="txtExpMonth" runat="server" data-vp="month"></asp:TextBox><br />
        Expiration Year:
        <asp:TextBox ID="txtExpYear" runat="server" data-vp="year"></asp:TextBox><br />
        <asp:HiddenField ID="hidToken" runat="server" />
        <asp:Button ID="btnSubmit" runat="server" text="Submit" OnClientClick="VivaPayments.cards.requestToken();return false;" />
    </form>
    <script type="text/javascript">
        $(document).ready(function () {
            if ($('#paymentform').length)
                VivaPayments.cards.setup({
                    publicKey: 'u3a1fcKsxynRZwY8zb++1utUYr1vjdGW6okiEX0pJBc=',
                    baseURL: 'http://demo.vivapayments.com/',
                    cardTokenHandler: function (response) {
                        if (!response.Error) {
                            $('#hidToken').val(response.Token);
                            $('#paymentform').submit();
                        }
                        else
                            alert(response.Error);
                    },
                    installmentsHandler: function (response) {
                        if (!response.Error) {
                            if (response.MaxInstallments == 0) {
                                $('#drpInstallments').empty();
                                $('#divInstallments').hide();
                                return;
                            }

                            $('#divInstallments').show();
                            for (i = 1; i <= response.MaxInstallments; i++) {
                                $('#drpInstallments').append($("<option>").val(i).text(i));
                            }
                        }
                        else
                            alert(response.Error);
                    }
                });
        });
    </script>

</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using RestSharp;

public partial class Default : System.Web.UI.Page
{
    private Guid MerchantId = new Guid("90DDA476-CF7C-4CFD-A9CB-23DFE11F131E");
    private string ApiKey = "XXXXXX";
    private string BaseApiUrl = "https://demo.vivapayments.com";
    private string PaymentsUrl = "/api/transactions";
    private string PaymentsCreateOrderUrl = "/api/orders";

    protected void PageLoad(object sender, EventArgs e)
    {
        if (Request.HttpMethod == "POST") {

            var orderCode = CreateOrder(10000);    //CALL TO CREATE AN ORDER. IF AN ORDER CODE ALREADY EXISTS FROM A PREVIOUS STEP, USE THAT ONE INSTEAD

            var cl = new RestClient(BaseApiUrl);
            cl.Authenticator = new HttpBasicAuthenticator(
                                    MerchantId.ToString(),
                                    ApiKey);

            var req = new RestRequest(PaymentsUrl, Method.POST);
            req.RequestFormat = DataFormat.Json;
            req.AddBody(new {
                OrderCode = orderCode,
                SourceCode = "Default",             //MAKE SURE THIS IS A SOURCE OF TYPE NATIVE/SIMPLE
                CreditCard = new {
                    Token = hidToken.Value.ToString()
                }
            });

            paymentform.Visible = false;

            var res = cl.Execute<TransactionResult>(req);
            if (res.Data != null && res.Data.ErrorCode == 0 && res.Data.StatusId == "F") {
                Response.Write(String.Format(
                    "Transaction was successful. TransactionId is {0}",
                    res.Data.TransactionId));
            }
            else{
                Response.Write(String.Format(
                    "Transaction failed. Error code was {0}",
                    res.Data.ErrorCode));
            }

        }
    }

    private long CreateOrder(long amount)
    {
        var cl = new RestClient(BaseApiUrl);
        cl.Authenticator = new HttpBasicAuthenticator(
                                MerchantId.ToString(),
                                ApiKey);

        var req = new RestRequest(PaymentsCreateOrderUrl, Method.POST);

        req.AddObject(new {
            Amount = 100,    // Amount is in cents
            SourceCode = "Default"
        });

        var res = cl.Execute<OrderResult>(req);

        if (res.Data != null && res.Data.ErrorCode == 0) {
            return res.Data.OrderCode;
        }
        else
            return 0;
    }

    public class OrderResult
    {
        public long OrderCode { get; set; }
        public int ErrorCode { get; set; }
        public string ErrorText { get; set; }
        public DateTime TimeStamp { get; set; }

    }

    public class TransactionResult
    {
        public string StatusId { get; set; }
        public Guid TransactionId { get; set; }
        public int ErrorCode { get; set; }
        public string ErrorText { get; set; }
        public DateTime TimeStamp { get; set; }
    }

}

The above sample receives the token along with all the clear text fields posted by the form. An order is created and a call to charge the card (given the token) takes place. The StatusId returned from the charge call is documented under Retrieve transactions.

If you have created the OrderCode in a previous step of your checkout process, you can skip the CreateOrder call.

You can view/clone the full working sample C# project via the Viva Wallet public GitHub page .

PCI standards, requirements and security considerations

The payments facilitated by our infrastructure are transmitted and processed using client-side encryption at all communications. Additionally we use PCI-PTS and FIPS 140-2 level 3 certified payment hardware security modules (HSMs), to perform key, card and PIN related cryptographic operations for the processing & storage of the cardholder data.

Card data is encrypted on the browser using industry best practices for protecting the user, relying on session isolation and TLS v1.2 cryptography, which in turn ensures unique keys per session with proof from replay attacks & man-in-the-middle attacks in the communications. The card tokenization process involves encryption of cardholder data under HSM-encrypted keys and association with unique-index reference to the card and authenticated API for the decryption.

Browser support

The SDK uses XMLHttpRequest and CORS which is supported by all modern browsers. The current SDK has been tested successfully with:

  • Firefox 65+
  • Chrome 73+
  • Chrome for Android 41+
  • Opera 27+
  • Safari 6.1+ (incl. iPhone 4S with iOS 6)
  • IE 10+ (including Windows Phone)