Quick Guide
Set up your merchant group account at https://dashboard.xiippy.ai/ A merchant group is a group of logically connected merchants, like members of a franchise. An independent merchant can be deemed a merchant group with a single member. Members of a merchant group (e.g. franchisees) should be invited by the head of group to create their accounts at https://dashboard.xiippy.ai/ManageEnterprise.
Set up your merchant account at https://dashboard.xiippy.ai/SetupMerchantAccount
Choose between a self-deployed instance of the SDK Bridge (which will have its own URL), or alternatively, use the cloud-based one at https://sdkbridge.xiippy.ai/
Log into the SDK Bridge instance using its URL and follow the prompts to create the cryptographic keys which will be used to transfer end-to-end encrypted data to the payers from the SDK Bridge instance, as well as to digitally-signed itemized invoices and receipts, as well as to create the 4 parameters that Xiippy's lightweight SDK requires to interact with the SDK Bridge instance and process payments using it, as follows:
A Merchant Group ID,
A Merchant ID,
A Base URL (which is normally the URL of the SDK Bridge instance you are interacting with)
A Secret Key (which has to be treated like a secret and maintained only at server-side with proper provisions and care applicable to secrets, never to be sent to client side)
Pick a relevant SDK for your desired software stack and include Xiippy's lightweight SDKs. We recommend you to use one of the available sample apps to get started quickly. All you need is the source code and the 4 config items that you need to set in the sample apps to run it and succesfully initiate your first payments.
git clone https://github.com/Xiippy/XiippySDKBridgeSampleAspNetApp
git clone https://github.com/Xiippy/XiippySDKBridgeSamplePHPApp
git clone https://github.com/Xiippy/XiippySDKBridgeSampleNodeJSApp
git clone https://github.com/Xiippy/XiippySDKBridgeSampleGoLangApp
Alternatively, follow the next steps by integrating the SDK with your existing payment pages by installing Xiippy's lightweight SDK packages
dotnet add package Xiippy.POSeComSDK.Light
composer require xiippy/posecomsdk
npm install xiippy.posecomsdk.light
go get github.com/Xiippy/Xiippy.POSeCommSDK.Light_GoLang
On your main payments page, include Xiippy's main client-side scripts
<script src="https://cdn.xiippy.ai/PaymentScripts/app.XiippyFrameSDK.bundle.js"></script>
Include the necessary JavaScript code on your page
@{if (!string.IsNullOrEmpty(Model.ErrorText))
{
<div class="alert alert-danger alert-dismissible fade show text-break" role="alert">
<p><strong>Error</strong></p>
<p> @Model.ErrorText</p>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true"></span>
</button>
</div>
}
}
<div id="frameContainer" style="width:100%; margin:0 auto 0 auto; min-height:300"></div>
<div id="diverror" style="width:100%; margin:0 auto 0 auto;"></div>
<script>
function initXiippyFrameSDK() {
// initialize parameters
var FrameContainerID = 'frameContainer';
// this parameter is generated by Xiippy's server-side SDK and has to be set from the server
var Url = '<%- Model.XiippyFrameUrl %>';
var sdkInstance = new XiippyFrameSDK.XiippyFrameSDK(FrameContainerID, Url);
// listen for events
sdkInstance.on('PaymentProcessed', (eventArgs) => {
// you need to implement payment success logic here
console.log('PaymentProcessed event was fired!', eventArgs);
});
sdkInstance.on('PaymentError', (eventArgs) => {
// you need to implement retrying or error handling logic here!
console.log('PaymentError event was fired!', eventArgs);
document.getElementById('diverror').innerText = eventArgs?.eventArgs?.error?.message;
});
}
// initialize the SDK upon page load
window.addEventListener("load", () => initXiippyFrameSDK(), false);
</script>
<?php if (!is_null($ErrorText)) { ?>
<div class="alert alert-danger alert-dismissible fade show text-break" role="alert">
<p><strong>Error</strong></p>
<p> <?= $ErrorText ?></p>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true"></span>
</button>
</div>
<?php } ?>
<div id="frameContainer" style="width:100%; margin:0 auto 0 auto; min-height:300"></div>
<div id="diverror" style="width:100%; margin:0 auto 0 auto;"></div>
<script src="https://cdn.xiippy.ai/PaymentScripts/app.XiippyFrameSDK.bundle.js"></script>
<script>
function initXiippyFrameSDK() {
// initialize parameters
var FrameContainerID = 'frameContainer';
// this parameter is generated by Xiippy's server-side SDK and has to be set from the server
var Url = '<?= $XiippyFrameUrl ?>';
var sdkInstance = new XiippyFrameSDK.XiippyFrameSDK(FrameContainerID, Url);
// listen for events
sdkInstance.on('PaymentProcessed', (eventArgs) => {
// you need to implement payment success logic here
console.log('PaymentProcessed event was fired!', eventArgs);
});
sdkInstance.on('PaymentError', (eventArgs) => {
// you need to implement retrying or error handling logic here!
console.log('PaymentError event was fired!', eventArgs);
document.getElementById('diverror').innerText = eventArgs?.eventArgs?.error?.message;
});
}
// initialize the SDK upon page load
window.addEventListener("load", () => initXiippyFrameSDK(), false);
</script>
<% if (Model.ErrorText) { %>
<div class="alert alert-danger alert-dismissible fade show text-break" role="alert">
<p><strong>Error</strong></p>
<p> <%= Model.ErrorText%></p>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true"></span>
</button>
</div>
<% } %>
<div id="frameContainer" style="width:100%; margin:0 auto 0 auto; min-height:300"></div>
<div id="diverror" style="width:100%; margin:0 auto 0 auto;"></div>
<script src="https://cdn.xiippy.ai/PaymentScripts/app.XiippyFrameSDK.bundle.js"></script>
<script>
function initXiippyFrameSDK() {
// initialize parameters
var FrameContainerID = 'frameContainer';
// this parameter is generated by Xiippy's server-side SDK and has to be set from the server
var Url = '<%- Model.XiippyFrameUrl %>';
var sdkInstance = new XiippyFrameSDK.XiippyFrameSDK(FrameContainerID, Url);
// listen for events
sdkInstance.on('PaymentProcessed', (eventArgs) => {
// you need to implement payment success logic here
console.log('PaymentProcessed event was fired!', eventArgs);
});
sdkInstance.on('PaymentError', (eventArgs) => {
// you need to implement retrying or error handling logic here!
console.log('PaymentError event was fired!', eventArgs);
document.getElementById('diverror').innerText = eventArgs?.eventArgs?.error?.message;
});
}
// initialize the SDK upon page load
window.addEventListener("load", () => initXiippyFrameSDK(), false);
</script>
{{ if .ErrorText }}
<div class="alert alert-danger alert-dismissible fade show text-break" role="alert">
<p><strong>Error</strong></p>
<p>{{ .ErrorText }}</p>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{{ end }}
<div id="frameContainer" style="width:100%; margin:0 auto 0 auto; min-height:300px;"></div>
<div id="diverror" style="width:100%; margin:0 auto 0 auto;"></div>
<script src="https://cdn.xiippy.ai/PaymentScripts/app.XiippyFrameSDK.bundle.js"></script>
<script>
function initXiippyFrameSDK() {
// initialize parameters
var FrameContainerID = 'frameContainer';
// this parameter is generated by Xiippy's server-side SDK and has to be set from the server
var Url = '{{ .XiippyFrameUrl }}';
var sdkInstance = new XiippyFrameSDK.XiippyFrameSDK(FrameContainerID, Url);
// listen for events
sdkInstance.on('PaymentProcessed', (eventArgs) => {
// you need to implement payment success logic here
console.log('PaymentProcessed event was fired!', eventArgs);
});
sdkInstance.on('PaymentError', (eventArgs) => {
// you need to implement retrying or error handling logic here!
console.log('PaymentError event was fired!', eventArgs);
document.getElementById('diverror').innerText = eventArgs?.eventArgs?.error?.message;
});
}
// initialize the SDK upon page load
window.addEventListener("load", () => initXiippyFrameSDK(), false);
</script>
On the back-end, on the payment page, include the right dependencies from the lightweight SDK.
using Xiippy.POSeComSDK.Light.Models;
using Xiippy.POSeComSDK.Light.XiippySDKBridgeApiClient;
require_once __DIR__ .'/vendor/xiippy/posecomsdk/src/Models/PaymentProcessingRequest.php';
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient\Constants;
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient;
use \Xiippy\POSeComSDK\Light\Models\PaymentProcessingRequest;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomer;
use \Xiippy\POSeComSDK\Light\Models\IssuerStatementRecord;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomerAddress;
use \Xiippy\POSeComSDK\Light\Models\StatementItem;
const posecomsdk = require('xiippy.posecomsdk.light');
const PaymentProcessingRequest = posecomsdk.PaymentProcessingRequest;
const IssuerStatementRecord = posecomsdk.IssuerStatementRecord;
const PaymentRecordCustomer = posecomsdk.PaymentRecordCustomer;
const PaymentRecordCustomerAddress = posecomsdk.PaymentRecordCustomerAddress;
const StatementItem = posecomsdk.StatementItem;
const XiippySDKBridgeApiClient = posecomsdk.XiippySDKBridgeApiClient;
const Utils = posecomsdk.Utils;
const Constants = posecomsdk.Constants;
import (
"github.com/Xiippy/Xiippy.POSeCommSDK.Light_GoLang/Models"
"github.com/Xiippy/Xiippy.POSeCommSDK.Light_GoLang/XiippySDKBridgeApiClient"
)
On the back-end, upon the initialization of the payment page, initialize the payment process by passing the right Merchant Group ID, Merchant ID, Base Address and Secret Key to the lightweight SDK functions.
/// <summary>
/// Page initialization
/// </summary>
/// <returns></returns>
public async Task<IActionResult> OnGetAsync()
{
try
{
// try initiating the payment and loading the payment card screen
XiippyFrameUrl = await InitiatePaymentAndGetiFrameUrlAsync();
}
catch (Exception x)
{
// show the error message, if any
ErrorText = x.ToString();
}
return Page();
}
/// <summary>
/// Initiate the payment flow and get the URL to be loaded in the iFrame
/// </summary>
/// <returns></returns>
public async Task<string> InitiatePaymentAndGetiFrameUrlAsync()
{
// depending on the basket, shipping and billing address entered, as well as amounts, the payment is initialized:
string StatementID = Guid.NewGuid().ToString();
string UniqueStatementID = Guid.NewGuid().ToString();
PaymentProcessingRequest req = new PaymentProcessingRequest
{
MerchantGroupID = config.MerchantGroupID,
MerchantID = config.MerchantID,
Amount = 2.5F,
Currency = "aud",
ExternalUniqueID = UniqueStatementID,
IsPreAuth = false,
IsViaTerminal = false,
// customer is optional
Customer = new PaymentRecordCustomer
{
CustomerAddress = new PaymentRecordCustomerAddress
{
CityOrSuburb = "Brisbane",
Country = "Australia",
FullName = "Full Name",
Line1 = "100 Queen St",
PhoneNumber = "+61400000000",
PostalCode = "4000",
StateOrPrivince = "Qld"
},
CustomerEmail = "dont@contact.me",
CustomerName = "Full Name",
CustomerPhone = "+61400000000"
},
IssuerStatementRecord = new IssuerStatementRecord
{
// this could be a different id than RandomStatementID which is a Xiippy identifier
UniqueStatementID = UniqueStatementID,
RandomStatementID = StatementID,
StatementCreationDate = DateTime.Now.ToUniversalTime().Ticks.ToString(),
StatementTimeStamp = DateTime.Now.ToString("yyyyMMddHHmmss"),
Description = "Test transaction #1",
DetailsInBodyBeforeItems = "Description on the receipt before items",
DetailsInBodyAfterItems = "Description on the receipt after items",
DetailsInFooter = "Description on the footer",
DetailsInHeader = "Description on the header",
StatementItems = new List<StatementItem>
{
new StatementItem
{
Description = "Description",
UnitPrice = 11,
Url = "Url",
Quantity = 1,
Identifier = "Identifier",
Tax=1,
TotalPrice=11
},
new StatementItem
{
Description = "Description2",
UnitPrice = 33,
Url = "Url2",
Quantity =1,
Identifier = "Identifier2",
Tax=3,
TotalPrice=33,
}
},
TotalAmount = 44,
TotalTaxAmount = 4
}
};
// instantiate the SDK objects and feed them with the right parameters
XiippySDKBridgeApiClient client = new XiippySDKBridgeApiClient(true, config.Config_ApiSecretKey, config.Config_BaseAddress, config.MerchantID, config.MerchantGroupID);
// initiate the payment
var response = await client.InitiateXiippyPayment(req);
string QueryString = Utils.Utils.BuildQueryString(new Dictionary<string, string>
{
{Constants.QueryStringParam_rsid,response.RandomStatementID },
{Constants.QueryStringParam_sts,response.StatementTimeStamp },
{Constants.QueryStringParam_ca,response.ClientAuthenticator },
{Constants.QueryStringParam_spw,"true" }, // show plain view
{Constants.QueryStringParam_MerchantID, config.MerchantID},
{Constants.QueryStringParam_MerchantGroupID, config.MerchantGroupID}, // important
{Constants.QueryStringParam_cs,response.ClientSecret },
{Constants.QueryStringParam_ShowLongXiippyText,"true" }, // show the long xiippy description text
});
string FullPaymentPageUrl = $"{config.Config_BaseAddress}/Payments/Process?{QueryString}";
Debug.WriteLine($"The payment page can not be browsed at '{FullPaymentPageUrl}'");
return FullPaymentPageUrl;
}
/// <summary>
/// Refunds a payment with RandomStatementID and StatementTimeStamp
/// </summary>
/// <param name="RandomStatementID"></param>
/// <param name="StatementTimeStamp"></param>
/// <param name="AmountInDollars">Optional, when null passed, refunds the full amount otherwise has to be smaller than the transaction amount</param>
/// <returns></returns>
public async Task RefundPaymentAsync(string RandomStatementID, string StatementTimeStamp, float? AmountInDollars)
{
RefundCardPaymentRequest req = new RefundCardPaymentRequest
{
MerchantGroupID = config.MerchantGroupID,
MerchantID = config.MerchantID,
RandomStatementID = RandomStatementID,
StatementTimestamp = StatementTimeStamp,
AmountInDollars= AmountInDollars
};
// instantiate the SDK objects and feed them with the right parameters
XiippySDKBridgeApiClient client = new XiippySDKBridgeApiClient(true, config.Config_ApiSecretKey, config.Config_BaseAddress, config.MerchantID, config.MerchantGroupID);
// initiate the payment
var response = await client.RefundCardPayment(req);
ProcessedMessage = @$"Refund was processed successfully. Response:\r\n{System.Text.Json.JsonSerializer.Serialize(response)}";
}
<?php
/*composer cmd :
composer config minimum-stability dev
composer require xiippy/posecomsdk
package url : https://packagist.org/packages/xiippy/posecomsdk
*/
require 'IndexPHPInitializer.php';
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/vendor/xiippy/posecomsdk/src/Models/PaymentProcessingRequest.php';
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient\Constants;
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient;
use \Xiippy\POSeComSDK\Light\Models\PaymentProcessingRequest;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomer;
use \Xiippy\POSeComSDK\Light\Models\IssuerStatementRecord;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomerAddress;
use \Xiippy\POSeComSDK\Light\Models\StatementItem;
use Xiippy\IndexPHPInitializer;
$XiippyFrameUrl = null;
$ErrorText = null;
try {
$XiippyFrameUrl = IndexPHPInitializer::InitiatePaymentNGetiFrameUrl();
} catch (Exception $e) {
$ErrorText = $e->getMessage();
}
?>
// In a seperate class, at "IndexPHPInitializer.php":
namespace Xiippy
{
require_once __DIR__ .'/vendor/autoload.php';
require_once __DIR__ .'/vendor/xiippy/posecomsdk/src/Models/PaymentProcessingRequest.php';
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient\Constants;
use \Xiippy\POSeComSDK\Light\XiippySDKBridgeApiClient;
use \Xiippy\POSeComSDK\Light\Models\PaymentProcessingRequest;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomer;
use \Xiippy\POSeComSDK\Light\Models\IssuerStatementRecord;
use \Xiippy\POSeComSDK\Light\Models\PaymentRecordCustomerAddress;
use \Xiippy\POSeComSDK\Light\Models\StatementItem;
// you need to generate these values after logging into your locally-deployed instance of the Xiippy SDKBridge, or, alternatively, the cloud-hosted one at https://sdkbridge.xiippy.ai.
// secrets have to be treated like secrets
// how to persist them and load them is all up to the developers
define("Config_BaseAddress" , "The base URL of the SDK Bridge instance"); // the base address when using the cloud hosted SDK bridge is https://sdkbridge.xiippy.ai
define("MerchantGroupID" , "Your Merchant Group ID, as reported by the SDK Bridge instance");
define("Config_ApiKey" , "API Secret Key, as reported by the SDK Bridge instance");
define("MerchantID" , "Your Merchant ID, as reported by the SDK Bridge instance");
class IndexPHPInitializer
{
public static function GUID()
{
if (function_exists('com_create_guid') === true)
{
return trim(com_create_guid(), '{}');
}
return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535));
}
public static function build_http_query( $query ){
$query_array = array();
foreach( $query as $key => $key_value ){
$query_array[] = urlencode( $key ) . '=' . urlencode( $key_value );
}
return implode( '&', $query_array );
}
public static function InitiatePaymentNGetiFrameUrl()
{
$UniqueID = IndexPHPInitializer::GUID();
$req = new PaymentProcessingRequest();
$req->MerchantGroupID = MerchantGroupID;
$req->MerchantID = MerchantID;
$req->Amount = 2.5;
$req->Currency = 'aud';
$req->ExternalUniqueID = $UniqueID;
$req->IsPreAuth = false;
$req->IsViaTerminal = false;
$req->Customer = new PaymentRecordCustomer();
$req->Customer->CustomerAddress = new PaymentRecordCustomerAddress();
$req->Customer->CustomerAddress->CityOrSuburb='Brisbane';
$req->Customer->CustomerAddress->Country='Australia';
$req->Customer->CustomerAddress->FullName='Full Name';
$req->Customer->CustomerAddress->Line1='100 Queen St';
$req->Customer->CustomerAddress->PhoneNumber='+61400000000';
$req->Customer->CustomerAddress->PostalCode='4000';
$req->Customer->CustomerAddress->StateOrPrivince='Qld';
$req->Customer->CustomerEmail = 'dont@contact.me';
$req->Customer->CustomerName = 'Full Name';
$req->Customer->CustomerPhone = '+61400000000';
$req->IssuerStatementRecord = new IssuerStatementRecord();
$req->IssuerStatementRecord->UniqueStatementID = $UniqueID;
$req->IssuerStatementRecord->RandomStatementID = POSeComSDK::GUID();
$req->IssuerStatementRecord->StatementCreationDate = '0';
$req->IssuerStatementRecord->StatementTimeStamp = (new \DateTime('NOW'))->format('YmdHis'); // important!
$req->IssuerStatementRecord->ProtocolVersion = 1;
$req->IssuerStatementRecord->Description = 'Test transaction #1';
$req->IssuerStatementRecord->DetailsInBodyBeforeItems = 'Description on the receipt before items';
$req->IssuerStatementRecord->DetailsInBodyAfterItems = 'Description on the receipt after items';
$req->IssuerStatementRecord->DetailsInHeader = 'Description on the footer';
$req->IssuerStatementRecord->DetailsInFooter = 'Description on the header';
$StatementItem = new StatementItem();
$StatementItem->Description = 'Description2';
$StatementItem->UnitPrice = 33;
$StatementItem->Url = 'Url2';
$StatementItem->Quantity = 1;
$StatementItem->Identifier = 'Identifier2';
$StatementItem->Tax = 3;
$StatementItem->TotalPrice = 33;
$req->IssuerStatementRecord->StatementItems[]=$StatementItem;
$req->IssuerStatementRecord->TotalAmount = 44;
$req->IssuerStatementRecord->TotalTaxAmount = 4;
$XiippySDKBridgeApiClient= new XiippySDKBridgeApiClient(true, Config_ApiKey, Config_BaseAddress.InitiateXiippyPaymentPath, MerchantID, MerchantGroupID);
$keys = $XiippySDKBridgeApiClient->InitiateXiippyPayment($req);
$result = array(Constants::$QueryStringParam_spw=>"true");
$result += array(Constants::$QueryStringParam_ShowLongXiippyText=>"true");
$result+= array(Constants::$QueryStringParam_MerchantID=> MerchantID);
$result+= array(Constants::$QueryStringParam_MerchantGroupID=> MerchantGroupID);
if(isset($keys->clientAuthenticator)){
$result+= array(Constants::$QueryStringParam_ca=> $keys->clientAuthenticator);
}
if(isset($keys->randomStatementID)){
$result+= array(Constants::$QueryStringParam_rsid=>$keys->randomStatementID);
}
if(isset($keys->statementTimeStamp)){
$result+= array(Constants::$QueryStringParam_sts=> $keys->statementTimeStamp);
}
if(isset($keys->clientSecret)){
$result+= array(Constants::$QueryStringParam_cs=> $keys->clientSecret);
}
$retval= Config_BaseAddress."/Payments/Process?".POSeComSDK::build_http_query($result);
return $retval;
}
}
}
// the express handler of the payment page
router.get('/', async (req, res) => {
var Model = {};
try {
// try initiating the payment and loading the payment card screen
Model.XiippyFrameUrl = await initiatePaymentNGetiFrameUrlAsync();
} catch (error) {
// show the error message, if any
Model.ErrorText = error.message;
}
res.render('index', { title: 'Sample Payment Page', Model: Model });
});
function getCurrentDateTime() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}${month}${day}${hours}${minutes}${seconds}`;
}
async function initiatePaymentNGetiFrameUrlAsync() {
const statementID = uuidv4(); // Assuming uuidv4() generates a UUID string
const uniqueStatementID = uuidv4(); // Assuming uuidv4() generates a UUID string
const req = new PaymentProcessingRequest();
req.MerchantGroupID = config.MerchantGroupID;
req.MerchantID = config.MerchantID;
req.Amount = 2.5;
req.Currency = "aud";
req.ExternalUniqueID = uniqueStatementID;
req.IsPreAuth = false;
req.IsViaTerminal = false;
// customer is optional
req.Customer = new PaymentRecordCustomer();
req.Customer.CustomerAddress = new PaymentRecordCustomerAddress();
req.Customer.CustomerAddress.CityOrSuburb = "Brisbane";
req.Customer.CustomerAddress.Country = "Australia";
req.Customer.CustomerAddress.FullName = "Full Name";
req.Customer.CustomerAddress.Line1 = "100 Queen St";
req.Customer.CustomerAddress.PhoneNumber = "+61400000000";
req.Customer.CustomerAddress.PostalCode = "4000";
req.Customer.CustomerAddress.StateOrPrivince = "Qld";
req.Customer.CustomerEmail = "dont@contact.me";
req.Customer.CustomerName = "Full Name";
req.Customer.CustomerPhone = "+61400000000";
req.IssuerStatementRecord = new IssuerStatementRecord();
req.IssuerStatementRecord.UniqueStatementID = uniqueStatementID;
req.IssuerStatementRecord.RandomStatementID = statementID;
req.IssuerStatementRecord.StatementCreationDate = Date.now().toString();
req.IssuerStatementRecord.StatementTimeStamp = getCurrentDateTime(); // Format: yyyyMMddHHmmss
req.IssuerStatementRecord.Description = "Test transaction #1";
req.IssuerStatementRecord.DetailsInBodyBeforeItems = "Description on the receipt before items";
req.IssuerStatementRecord.DetailsInBodyAfterItems = "Description on the receipt after items";
req.IssuerStatementRecord.DetailsInFooter = "Description on the footer";
req.IssuerStatementRecord.DetailsInHeader = "Description on the header";
req.IssuerStatementRecord.TotalAmount = 44;
req.IssuerStatementRecord.TotalTaxAmount = 4;
var StatementItem1 = new StatementItem();
StatementItem1.Description = "Description";
StatementItem1.UnitPrice = 11;
StatementItem1.Url = "Url";
StatementItem1.Quantity = 1;
StatementItem1.Identifier = "Identifier";
StatementItem1.Tax = 1;
StatementItem1.TotalPrice = 11;
var StatementItem2 = new StatementItem();
StatementItem2.Description = "Description2";
StatementItem2.UnitPrice = 33;
StatementItem2.Url = "Url2";
StatementItem2.Quantity = 1;
StatementItem2.Identifier = "Identifier2";
StatementItem2.Tax = 3;
StatementItem2.TotalPrice = 33;
req.IssuerStatementRecord.StatementItems = [];
req.IssuerStatementRecord.StatementItems.push(StatementItem1);
req.IssuerStatementRecord.StatementItems.push(StatementItem2);
const client = new XiippySDKBridgeApiClient(true, config.Config_ApiSecretKey, config.Config_BaseAddress, config.MerchantID, config.MerchantGroupID);
const response = await client.InitiateXiippyPayment(req);
const queryString = Utils.BuildQueryString({
[Constants.QueryStringParam_rsid]: response.RandomStatementID,
[Constants.QueryStringParam_sts]: response.StatementTimeStamp,
[Constants.QueryStringParam_ca]: response.ClientAuthenticator,
[Constants.QueryStringParam_spw]: "true", // show plain view
[Constants.QueryStringParam_MerchantID]: config.MerchantID,
[Constants.QueryStringParam_MerchantGroupID]: config.MerchantGroupID, // important
[Constants.QueryStringParam_cs]: response.ClientSecret,
[Constants.QueryStringParam_ShowLongXiippyText]: "true" // show the long xiippy description text
});
const fullPaymentPageUrl = `${config.Config_BaseAddress}/Payments/Process?${queryString}`;
console.log(`The payment page can be browsed at '${fullPaymentPageUrl}'`);
return fullPaymentPageUrl;
}
// the main handler of the payment page
func HomeHandler(w http.ResponseWriter, r *http.Request) {
// try initiating the payment and loading the payment card screen
XiippyFrameUrl, err := InitiatePaymentNGetiFrameUrl()
data := PageData{
XiippyFrameUrl: XiippyFrameUrl,
}
if err != nil {
// show the error message, if any
data.ErrorText = err.Error()
}
tmpl, err := template.ParseFiles("templates/layout.html", "templates/home.html")
if err != nil {
// show the error message, if any
data.ErrorText = err.Error()
}
err = tmpl.ExecuteTemplate(w, "layout", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func BuildQueryString(keyValuePairs map[string]string) string {
queryString := url.Values{}
for key, value := range keyValuePairs {
queryString.Add(key, value)
}
return queryString.Encode()
}
func InitiatePaymentNGetiFrameUrl() (string, error) {
// depending on the basket, shipping and billing address entered, as well as amounts, the payment is initialized:
StatementID := uuid.New().String()
UniqueStatementID := uuid.New().String()
req := Models.PaymentProcessingRequest{
MerchantGroupID: config.MerchantGroupID,
MerchantID: config.MerchantID,
Amount: 2.5,
Currency: "aud",
ExternalUniqueID: UniqueStatementID,
IsPreAuth: false,
IsViaTerminal: false,
// customer is optional
Customer: &Models.PaymentRecordCustomer{
CustomerAddress: Models.PaymentRecordCustomerAddress{
CityOrSuburb: "Brisbane",
Country: "Australia",
FullName: "Full Name",
Line1: "100 Queen St",
PhoneNumber: "+61400000000",
PostalCode: "4000",
StateOrPrivince: "Qld",
},
CustomerEmail: "dont@contact.me",
CustomerName: "Full Name",
CustomerPhone: "+61400000000",
},
IssuerStatementRecord: &Models.IssuerStatementRecord{
// this could be a different id than RandomStatementID which is a Xiippy identifier
UniqueStatementID: UniqueStatementID,
RandomStatementID: StatementID,
StatementCreationDate: time.Now().UTC().String(),
StatementTimeStamp: time.Now().Format("20060102150405"),
Description: "Test transaction #1",
DetailsInBodyBeforeItems: "Description on the receipt before items",
DetailsInBodyAfterItems: "Description on the receipt after items",
DetailsInFooter: "Description on the footer",
DetailsInHeader: "Description on the header",
StatementItems: []Models.StatementItem{
{
Description: "Description",
UnitPrice: 11,
Url: "Url",
Quantity: 1,
Identifier: "Identifier",
Tax: 1,
TotalPrice: 11,
},
{
Description: "Description2",
UnitPrice: 33,
Url: "Url2",
Quantity: 1,
Identifier: "Identifier2",
Tax: 3,
TotalPrice: 33,
},
},
TotalAmount: 44,
TotalTaxAmount: 4,
},
}
// instantiate the sdk client and pass the parameters
client := XiippySDKBridgeApiClient.NewXiippySDKBridgeApiClient(true, config.Config_ApiSecretKey, config.Config_BaseAddress, config.MerchantID, config.MerchantGroupID)
// initiate the payment
response, err := client.InitiateXiippyPayment(&req)
if err != nil {
return "", err
}
// compile the parameters required to load and initialize the payments screen
QueryString := BuildQueryString(map[string]string{
XiippySDKBridgeApiClient.QueryStringParamRsid: response.RandomStatementID,
XiippySDKBridgeApiClient.QueryStringParamSts: response.StatementTimeStamp,
XiippySDKBridgeApiClient.QueryStringParamCa: response.ClientAuthenticator,
XiippySDKBridgeApiClient.QueryStringParamSpw: "true", // show plain view
XiippySDKBridgeApiClient.QueryStringParamMerchantID: config.MerchantID,
XiippySDKBridgeApiClient.QueryStringParamMerchantGroupID: config.MerchantGroupID, // important
XiippySDKBridgeApiClient.QueryStringParamCs: response.ClientSecret,
XiippySDKBridgeApiClient.QueryStringParamShowLongXiippyText: "true", // show the long xiippy description text
})
FullPaymentPageUrl := fmt.Sprintf("%s/Payments/Process?%s", config.Config_BaseAddress, QueryString)
// optional
fmt.Printf("The payment page can not be browsed at '%s'\n", FullPaymentPageUrl)
return FullPaymentPageUrl, nil
}
Last updated