Embedded Payment Form (URL Page)

Step 1: Start Transaction

Merchant server only

These code samples show how you can start a transaction from your merchant server and generate a transaction token that you can then use in the client-side sdk to continue the transaction flow.


Step 2: Present payment form

Client-side only

After setting up a way to get a transaction token on your server, you will now need to retrieve that token client-side and use it to load the emergepay form.

Note

You must supply Gravity Payments with a valid parent domain. Connect with your Integration Specialist for more information.

<div class="iframeContainer">
    <div class="headerRow"><span id="closeBtn" class="closeBtn">×</span></div>
    <div id="iframeDiv"></div>
</div>

<!-- 
Load emergepay url page javascript file. 
NOTE: make sure you replace assets_url with the correct url for the environment you're working in. 
-->

<script src="assets_url/cip-hosted-url.js"></script>

<!-- Use the emergepay library -->
<script>
    var iframe = document.createElement("iframe");
    iframe.id = 'cip-hosted-urlpage';
    iframe.style.display = 'none';
    $("#iframeDiv").append(iframe);

    window.onload = function() {
        // set up event listener on Pay With Card button
        $('#startTransBtn').on('click', function (e) {
            e.preventDefault();
            // get a transactionToken serverside
            getToken().then(function (transactionToken) {
                //initialize the emergepay url library.
                var urlPage = emergepayUrlPage.init({
                    // (optional) Callback function that gets called after a successful transaction
                    onTransactionSuccess: function (approvalData) {
                        console.log("Approval Data", approvalData);
                        $(".iframeContainer").hide();
                    },
                    // (optional) Callback function that gets called after a failure occurs during the transaction (such as a declined card)
                    onTransactionFailure: function (failureData) {
                        console.log("Failure Data", failureData);
                    }
                });
                                // set the source of the iframe to the emergepay page.
                iframe.src = urlPage.getUrl(transactionToken);
                iframe.style.display = 'block';
                $(".iframeContainer").show();
            });
        });

        $("#closeBtn").on('click', function (e) {
            e.preventDefault();
            $(".iframeContainer").hide();
        });

        //this function makes a call to your server to get a transaction token
        function getToken(amount) {
            return new Promise(function (resolve, reject) {
                $.ajax({
                    url: 'http://localhost:5555/start-transaction',
                    type: 'POST',
                    dataType: 'json',
                    contentType: 'application/json'
                })
                .done(function(data) {
                    if (data.transactionToken) resolve(data.transactionToken);
                    else reject('Error getting transaction token');
                })
                .fail(function(err) {
                    reject(err);
                });
            });
        }
    }
</script>

If you’re wrapping the emergepay form in your own iframe and add your own close button, we recommend canceling the transaction when the close button is clicked by making a request to the following endpoint:

DELETE {environment_url}/transactions/{xtoken}

This will ensure that the transaction is canceled and the transaction token can no longer be used.


Step 3: Transaction results

Merchant server only

We strongly recommend using postback or server-side results retrieval from your application unless your application will be used exclusively by trusted users, such as cashiers.

Results Options

  • Postback – when a transaction completes, Gravity Payments will POST the results back to a URL you’ve pre-defined with your integration specialist.
  • Polling (aka retrieval) – Your app will query Gravity Payments using a unique externalTransactionId that your application created at the start of the transaction.
  • Callback – the results will be made available to the client side via callback functions passed in step 2 above.

Postback

HMAC Signature Validation

Post-back results should be verified using the HMAC signature found in the request header.

  • one-way SHA-512 message digest
  • encrypted using a secret passphrase you setup with your integration specialist and is then base64 encoded
  • digest is included in the request header as hmac-signature

Verify HMAC signature

  1. Encrypt the request body using the SHA512 hash algorithm and your secret key
  2. Base64 encode the result
  3. Compare the resulting value with the hmac-signature header value

What's a 'secret passphrase'?

Similar to the OID and authToken, the secret passphrase is a unique variable that is tied to each individual merchant account.

This is the recommended way to retrieve
transaction results.
var express = require("express");
var cors    = require("cors");
var crypto  = require("crypto");

var app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.post("/PostBackListener", (req, res) => {
    var hmacSignature = req.header("hmac-signature");
    var rawData = req.body;
    var jsonData = JSON.stringify(rawData);

    var signatureMatched = false;

    if (hmacSignature) {
        signatureMatched = verifyHmacSignature(hmacSignature, jsonData);
    }

    //if the hmac signature matched, the response body data is valid
    if (signatureMatched) {
        //do something with the transaction result
    }

    res.sendStatus(200);
});

function verifyHmacSignature(hmacSignature, data) {
    //this is the secret pass phrase you supplied to ChargeItPro
    var secretKey = "cipDemoListenerKey";

    var hmac = crypto.createHmac("sha512", secretKey);
    hmac.update(data);
    return hmac.digest("base64") === hmacSignature;
}

console.log("listening on port 5555");
app.listen(5555);
import * as express from 'express';
import * as cors from 'cors';
import * as crypto from 'crypto';

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.post("/PostBackListener", (req, res) => {
    const hmacSignature = req.header("hmac-signature");
    const rawData = req.body;
    const jsonData = JSON.stringify(rawData);

    let signatureMatched = false;

    if (hmacSignature) {
        signatureMatched = verifyHmacSignature(hmacSignature, jsonData);
    }

    //if the hmac signature matched, the response body data is valid
    if (signatureMatched) {
        //do something with the transaction result
    }

    res.sendStatus(200);
});

function verifyHmacSignature(hmacSignature: string, data: string): boolean {
    //this is the secret pass phrase you supplied to ChargeItPro
    const secretKey = "cipDemoListenerKey";

    const hmac = crypto.createHmac("sha512", secretKey);
    hmac.update(data);
    return hmac.digest("base64") === hmacSignature;
}

console.log("listening on port 5555");
app.listen(5555);
<?php

$headers = getallheaders();
$body = file_get_contents("php://input");
$jsonData = json_encode(json_decode($body));

$signatureMatched = false;

if (array_key_exists("hmac-signature", $headers)) {
    $hmacSignature = $headers["hmac-signature"];

    $signatureMatched = verifyHmacSignature($hmacSignature, $jsonData);
}

// if the hmac signature matched, the response body data is valid
if ($signatureMatched) {
    // do something with the transaction result
}

function verifyHmacSignature(string $hmacSignature, string $data) {
    // this is the secret pass phrase you supplied to ChargeItPro
    $secretKey = "yourSecretPassPhrase";

    $hmac = hash_hmac("sha512", $data, $secretKey, true);

    return base64_encode($hmac) == $hmacSignature;
}
[HttpPost]
public void PostBackListener()
{
  var reader = new StreamReader(Request.Body);
  var bodyContents = reader.ReadToEnd();
  var transactionResult = JsonConvert.DeserializeObject(bodyContents);
  var rawData = JsonConvert.DeserializeObject(bodyContents);
  var jsonData = JsonConvert.SerializeObject(rawData);

  //verify the hmac signature with our secret pass phrase
  bool hmacSignatureExists = Request.Headers.TryGetValue("hmac-signature", out var hmacSignature);
  bool signatureMatched = false;

  if (hmacSignatureExists)
  {
    string signature = hmacSignature.ToString();
    byte[] data = Encoding.UTF8.GetBytes(jsonData);
    signatureMatched = VerifyHmacSignature(signature, data);
  }

  //if the hmac signature matched, the response body data is valid
  if (signatureMatched)
  {
        //do something with the transaction result
  }
}

private bool VerifyHmacSignature(string hmacSignature, byte[] data)
{
  //this is the secret pass phrase you supplied to ChargeItPro
  const string secretKey = "yourSecretPassPhrase";

  using (HMACSHA512 hmac = new HMACSHA512(Encoding.UTF8.GetBytes(secretKey)))
  {
    byte[] computedHash = hmac.ComputeHash(data);
    string computedSignature = Convert.ToBase64String(computedHash);
    return hmacSignature == computedSignature;
  }
}

Retrieval

This sample code can be used to implement a polling model for fetching results.

This sample code can be used to implement 
a polling model for fetching results.
//install the module below with the following command:
//npm install emergepay-sdk
var emergepaySdk = require('emergepay-sdk').emergepaySdk;

//Ensure that you replace these with valid values before trying to issue a request
var oid = 'your_oid';
var authToken = 'your_authToken';
var environmentUrl = 'environment_url';

var emergepay = new emergepaySdk({oid: oid, authToken: authToken, environmentUrl: environmentUrl});

//Ensure that you supply a valid external transaction id before trying to run the retrieval function.
emergepay.retrieveTransaction("your_external_transaction_id")
.then(function(response) {
    var transactionResponse = response.data;
})
.catch(function(error) {
    throw error;
});
//install the module below with the following command:
//npm install emergepay-sdk
import {emergepaySdk} from "emergepay-sdk";

//Ensure that you replace these with valid values before trying to issue a request
const oid: string = "your_oid";
const authToken: string = "your_authToken";
const environmentUrl: string = "environment_url";
const emergepay: emergepaySdk = new emergepaySdk({oid, authToken, environmentUrl});

//Ensure that you supply a valid external transaction id before trying to run the retrieval function.
emergepay.retrieveTransaction("your_external_transaction_id")
.then(response => {
    const transactionResponse = response.data;
})
.catch(error => {
    throw error;
});
<?php

//Configure your oid and auth token. These are supplied by ChargeItPro.
//Note: Make sure you set these before attempting to retrieve transaction results.
$oid = 'your_oid';
$authToken = 'your_authToken';

//Set the external transaction id of the transaction you want to retrieve from ChargeItPro.
//Note: Make sure you set this before attempting to retrieve transaction results.
$externalTransactionId = '';

//Configure the environmentUrl. This is provided by ChargeItPro.
$environmentUrl = 'environment_url';
$url = $environmentUrl . '/orgs/' . $oid . '/transactions/' . $externalTransactionId;

//Configure the request
$request = curl_init($url);
curl_setopt($request, CURLOPT_HEADER, false);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer ' . $authToken));

//Issue the request and get the result
$response = curl_exec($request);
curl_close($request);

echo $response;
public static async Task RetrieveTransaction()
{
  var response = new object();

  //Ensure these are set before trying to issue the request.
  //Please contact ChargeItPro to get these values.
  const string OID = "your_oid";
  const string AUTH_TOKEN = "your_authToken";
  const string ENDPOINT_URL = "environment_url";

  //Ensure the externalTransactionId is set to the transaction you want to look up.
  string externalTransactionId = "your_external_transaction_id";

  string url = $"{ENDPOINT_URL}/orgs/{OID}/transactions/{externalTransactionId}";

  try
  {
    using (var client = new HttpClient())
    {
      HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
      request.Headers.Add("Authorization", $"Bearer {AUTH_TOKEN}");

      var httpResponse = await client.SendAsync(request);
      var data = await httpResponse.Content.ReadAsStringAsync();
      response = JsonConvert.DeserializeObject(data);
    }
  }
  catch (Exception exc)
  {
    throw exc;
  }

  return response;
}

Callback

An example of how to utilize these callback functions can be seen in Step 2.

An example of how to utilize these callback
functions can be seen in step 2.
//these are both optional functions that can be passed into the emergepay constructor (see the "Present ChargeItPro Form" section above). 
//Both will contain the appropriate results from running the transaction
onTransactionSuccess: function (approvalData) {
  console.log("Approval Data", approvalData);
}

onTransactionFailure: function (failureData) {
  console.log("Failure Data", failureData);
}

Account Card Type Values

Card Brand Response Code
Mastercard MC
Diners Club DN
Visa VS
JCB JC
American Express AX
Discover DC

Example transaction result responses

Each tab shows an example response from the respective retrieval method.
{
    "accountCardType": "VS",
    "accountEntryMethod": "Keyed",
    "accountExpiryDate": "1027",
    "amount": "0.01",
    "amountBalance": "",
    "amountProcessed": "0.01",
    "amountTaxed": "0.00",
    "amountTipped": "0.00",
    "approvalNumberResult": "256171",
    "avsResponseCode": "Y",
    "avsResponseText": "Address: Match & 5 Digit Zip: Match",
    "batchNumber": "0",
    "billingName": "",
    "cashier": "",
    "cvvResponseCode": "P",
    "cvvResponseText": "Not Processed",
    "externalTransactionId": "4b07fa33-c03e-48c0-ba3c-0e02d98f5fb3",
    "isPartialApproval": false,
    "maskedAccount": "************1111",
    "resultMessage": "Approved",
    "resultStatus": "true",
    "transactionReference": "",
    "transactionType": "CreditSale",
    "uniqueTransId": "aec21bf6779544f4be812c29beba7024-a5300e56fb6b40ea9ee28b6c14e6e3ed"
}
{
   "transactionResponse": {
      "accountCardType": "VS",
      "accountEntryMethod": "Keyed",
      "accountExpiryDate": "1027",
      "amount": "0.01",
      "amountBalance": "",
      "amountProcessed": "0.01",
      "amountTaxed": "0.00",
      "amountTipped": "0.00",
      "approvalNumberResult": "256171",
      "avsResponseCode": "Y",
      "avsResponseText": "Address: Match & 5 Digit Zip: Match",
      "batchNumber": "0",
      "billingName": "",
      "cashier": "",
      "cvvResponseCode": "P",
      "cvvResponseText": "Not Processed",
      "externalTransactionId": "4b07fa33-c03e-48c0-ba3c-0e02d98f5fb3",
      "isPartialApproval": false,
      "maskedAccount": "************1111",
      "resultMessage": "Approved",
      "resultStatus": "true",
      "transactionReference": "",
      "transactionType": "CreditSale",
      "uniqueTransId": "aec21bf6779544f4be812c29beba7024-a5300e56fb6b40ea9ee28b6c14e6e3ed"
  }
}
{
    "accountCardType": "VS",
    "accountEntryMethod": "Keyed",
    "accountExpiryDate": "1027",
    "amount": "0.01",
    "amountBalance": "",
    "amountProcessed": "0.01",
    "amountTaxed": "0.00",
    "amountTipped": "0.00",
    "approvalNumberResult": "256171",
    "avsResponseCode": "Y",
    "avsResponseText": "Address: Match & 5 Digit Zip: Match",
    "batchNumber": "0",
    "billingName": "",
    "cashier": "",
    "cvvResponseCode": "P",
    "cvvResponseText": "Not Processed",
    "externalTransactionId": "4b07fa33-c03e-48c0-ba3c-0e02d98f5fb3",
    "isPartialApproval": false,
    "maskedAccount": "************1111",
    "resultMessage": "Approved",
    "resultStatus": "true",
    "transactionReference": "",
    "transactionType": "CreditSale",
    "uniqueTransId": "aec21bf6779544f4be812c29beba7024-a5300e56fb6b40ea9ee28b6c14e6e3ed"
}

Print or Email Receipt

Your application should now analyze the results and asks for another form of payment when the card is partially approved or declined. If approved, your application should print\email a receipt.


Step 4: Transaction acknowledgment

Merchant server only

What is the purpose of Transaction acknowledgment?

The purpose of the transaction acknowledgement endpoint is to close the communication loop for a transaction and signal to emergepay that you’ve received the transaction response.

Here are some details about the endpoint:

  • emergepay will reply with a 200 success status when the acknowledgment is received.
  • No specific error message will be returned in the event of an error and the only action you should take when an error does occur is retry.

Best Practices

  • Ensure that the transaction acknowledgment is sent after the transaction response is received
  • Ensure that the transaction acknowledgment, after receiving back a successful 200 status, is not sent again
  • Use a backoff/retry algorithm when an error is received from the endpoint
Examples of transaction acknowledgement
//install the module below with the following command:
//npm install emergepay-sdk
var emergepaySdk = require('emergepay-sdk').emergepaySdk;

//Ensure that you replace these with valid values before trying to issue a request
var oid = 'your_oid';
var authToken = 'your_authToken';
var environmentUrl = 'environment_url';

var emergepay = new emergepaySdk({oid: oid, authToken: authToken, environmentUrl: environmentUrl});

//Ensure that you supply a valid external transaction id before trying to run the acknowledge function.
emergepay.acknowledge("your_external_transaction_id")
    .catch(function(error) {
        console.log("need to retry");
    });
//install the module below with the following command:
//npm install emergepay-sdk
import {emergepaySdk} from "emergepay-sdk";

const oid: string = "your_oid";
const authToken: string = "your_authToken";
const environmentUrl: string = "environment_url";

const emergepay: emergepaySdk = new emergepaySdk({ oid, authToken, environmentUrl });

emergepay.acknowledge("your_external_transaction_id")
    .catch(error => {
        console.log("need to retry");
    });
<?php

//Configure your oid and auth token. These are supplied by ChargeItPro.
//Note: Make sure you set these before attempting to retrieve transaction results.
$oid = 'your_oid';
$authToken = 'your_authToken';

//Set the external transaction id of the transaction you want to retrieve from ChargeItPro.
//Note: Make sure you set this before attempting to retrieve transaction results.
$externalTransactionId = 'your_external_transaction_id';

//Configure the environmentUrl. This is provided by ChargeItPro.
$environmentUrl = 'environment_url';
$url = $environmentUrl . '/orgs/' . $oid . '/transactions/acknowledgements/' . $externalTransactionId;

//Configure the request
$request = curl_init($url);
curl_setopt($request, CURLOPT_HEADER, false);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer ' . $authToken));


//Issue the request and get the result
$response = curl_exec($request);

if (curl_getinfo($request)['http_code'] !== 200) {
    echo 'need to retry';
}

curl_close($request);
public static async Task AcknowledgeAsync()
{
    //Ensure these are set before trying to issue the request.
    //Please contact ChargeItPro to get these values.
    const string OID = "your_oid";
    const string AUTH_TOKEN = "your_authToken";
    const string ENDPOINT_URL = "environment_url";

    //Ensure that you supply a valid external transaction id before trying to run this function.
    string externalTransactionId = "your_external_transaction_id";

    string url = $"{ENDPOINT_URL}/orgs/{OID}/transactions/acknowledgements/{externalTransactionId}";

    try
    {
        using (var client = new HttpClient())
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, url);
            request.Headers.Add("Authorization", $"Bearer {AUTH_TOKEN}");

            var httpResponse = await client.SendAsync(request);

            if (httpResponse.StatusCode != System.Net.HttpStatusCode.OK)
            {
                Console.WriteLine("need to retry");
            }
        }
    }
    catch (Exception exc)
    {
        Console.WriteLine("need to retry");
    }
}

Transaction acknowledgement path parameter requirements

NameDetailsRequiredDescription
oidstringYesThe merchant identifier of the merchant that ran the transaction to acknowledge
externalTransactionIdType: v4 uuidYesA reference to the transaction to acknowledge. This value must be the Version-4 UUID that was generated by you in the creation of the transaction.

Step 5: Are you using a payment device?

Emergepay makes it easy to add a payment device to your integration. Take a look at our supported payment devices. Additionally, since emergepay is platform and OS agnostic, we are able to process transactions from any platform and OS.

Our card-present solution uses the same endpoints as our card not present solution, only requiring a few extra fields and methods, please review them below.

Available Transaction Types

  • CreditSale
  • CreditReturn
  • CreditAuth
  • RequestSignature

Transaction Types Not Available

  • ACHSale
  • ACHReturn
  • CreditSaveCard

Additional transaction input fields required

NameDetailsRequiredDescription
device_nameType: string
Max length: 50
YesThe name of the device to use for the transaction.
tip_promptType: string
Enum: "true" | "false"
NoAn optional parameter that, when set to "true", will cause the device to prompt the customer to enter a tip amount. The tip amount entered by the customer on the device will be added to the value of "base_amount" to calculate the transaction total.
signature_captureType: string
Enum: "true" | "false"
NoDefault: "false". An optional parameter for controlling the signature prompt on capable devices. If set to "true", the device will prompt the user to draw their signature on the device screen after they enter their card. The results will be available in the "signature" section of the transaction results as a Base64 encoded image.
signature_requiredType: string
Enum: "true" | "false"
NoDefault: "false". Determines whether entering a signature is required. Requires "signature_capture" to be set to "true.

Partial Approval Support

Card brand regulations require the support of partial approvals when using a payment device; a partial approval occurs when a user has insufficient funds on a debit or gift card, but the device accepts the payment for the amount on the card anyway.
  • For example, you initiate a sale for $100.00, but the customer only has $75 on their card—the system will approve the transaction for $75.00, and inform you that a partial approval was processed, you’ll then need to initiate a new sale for the remaining $25.00
  • The amountProcessed and isPartialApproval fields in our results can all be used to check for a partial approval

Tipping Support

The “tip_amount” and “prompt_tip” fields cannot both hold positive values, as they are alternative ways to process a tip. For instance, if “prompt_tip” is set to “true”, then the “tip_amount” parameter must be excluded from the request or set to “0.00”.

Input fields for RequestSignature

Request signature allows you to request a signature outside of a payment transaction.

Device Support

This feature is only available on the following devices:

  • Clover Flex
  • Clover Mini
NameDetailsRequiredDescription
external_tran_idType: v4 uuidYesA unique transaction identifier (must be a Version-4 UUID) for each transaction. This value is used to look up transaction results as well as confirm to the merchant and emergepay that a transaction was completed.
device_nameType: string
Max length: 50
YesThe name of the device to use for the transaction.
cashier_idType: string
Max length: 150
NoThe name of the cashier that ran the transaction.
transaction_referenceType: string
Min length: 3
Max length: 65
NoThe order id associated with the transaction.
confirmation_textType: string
Min length: 3
Max length: 200
NoText to display on the screen above the signature prompt.
This code demonstrates how to initiate a RequestSignature.
The transaction token retrieved here should be used on the 
client side to initiate the device's requestSignature screen.
//install the modules below with the following command:
//npm install -D express body-parser cors emergepay-sdk
var express = require("express");
var bodyParser = require("body-parser");
var cors = require("cors");
var sdk = require("emergepay-sdk");

//Ensure that you replace these with valid values before trying to issue a request
var oid = "your_oid";
var authToken = "your_authToken";
var environmentUrl = "environment_url";
var emergepay = new sdk.emergepaySdk({ oid: oid, authToken: authToken, environmentUrl: environmentUrl });

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());

//The client side can hit this endpoint by issuing a POST request to
//localhost:5555/start-transaction
//device_name and external_tran_id are required in the fields array.
app.post("/start-transaction", function (req, res) {
    var amount = "0.01";
    var config = {
        transactionType: sdk.TransactionType.RequestSignature,
        method: "modal",
        fields: [
            {
                id: "external_tran_id",
                value: emergepay.getExternalTransactionId()
            },
            {
                id: "device_name", 
                value: "{your_device_name}"
            }
        ]
    };
  
    emergepay.startTransaction(config)
    .then(function (transactionToken) {
        res.send({
            transactionToken: transactionToken
        });
    })
    .catch(function (err) {
        res.send(err.message);
    });
});

console.log("listening on port 5555");
app.listen(5555);
//install the modules below with the following command:
//npm install -D express body-parser cors emergepay-sdk
import * as express from "express";
import * as bodyParser from "body-parser";
import * as cors from "cors";
import {emergepaySdk, TransactionType} from "emergepay-sdk";

//Ensure that you replace these with valid values before trying to issue a request
const oid: string = "your_oid";
const authToken: string = "your_authToken";
const environmentUrl: string = "environment_url";
const emergepay: emergepaySdk = new emergepaySdk({oid, authToken, environmentUrl});

const app: any = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(cors());

//The client side can hit this endpoint by issuing a POST request to
//localhost:5555/start-transaction
//device_name and external_tran_id are required in the fields array.
app.post("/start-transaction", (req, res) => {
    const amount = "0.01";
    const config: any = {
        transactionType: TransactionType.RequestSignature,
        method: "modal",
        fields: [
            {
                id : "external_tran_id",
                value : emergepay.getExternalTransactionId()
            },
            {
                id : "device_name",
                value : "{your_device_name}"
            }
        ]
    };

    emergepay.startTransaction(config)
        .then(transactionToken => {
            res.send({
                transactionToken: transactionToken
            });
        })
        .catch(err => {
            res.send(err.message);
        });
});

console.log("listening on port 5555");
app.listen(5555);
<?php

//Configure your oid, authToken, and environmentUrl.
//These are required and supplied by ChargeItPro.
//Note: Make sure you set these before attempting to retrieve transaction results.
$oid = 'your_oid';
$authToken = 'your_authToken';
$environmentUrl = 'environment_url';

$url = $environmentUrl . '/orgs/' . $oid . '/transactions/start';

//Set up the request body.
//device_name and external_tran_id are required in the fields array. 
$body = array(
    'transactionType' => 'CreditAuth',
    'method' => 'modal',
    'fields' => array(
      array('id' => 'external_tran_id', 'value' => GUID()),
      array('id' => 'device_name', 'value' => 'your_device_name')
    )
  )
);

//Configure the request
$request = curl_init($url);
curl_setopt($request, CURLOPT_HEADER, false);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer ' . $authToken));
curl_setopt($request, CURLOPT_POST, true);
curl_setopt($request, CURLOPT_POSTFIELDS, json_encode($body));

//Issue the request and get the response
$response = curl_exec($request);
curl_close($request);

echo $response;

//Helper function used to generate a GUID/UUID
//source: http://php.net/manual/en/function.com-create-guid.php#99425
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 async Task StartTransactionAsync(StartTransactionModel config)
{
  var response = new object();

  //Ensure these are set before trying to issue the request.
  //Please contact ChargeItPro to get these values.
  const string OID = "your_oid";
  const string AUTH_TOKEN = "your_authToken";
  const string ENDPOINT_URL = "environment_url";

  string url = $"{ENDPOINT_URL}/orgs/{OID}/transactions/start";

  //all of the values in fields are strings
  var contents = new
  {
    transactionData = new
    {
      transactionType = "RequestSignature",
      method = "modal",
      fields = new[] {
        new { id = "external_tran_id",      value = Guid.NewGuid().ToString() },
        new { id = "device_name",           value = config.DeviceName }
      }
    }
  };

  try
  {
    using (var client = new HttpClient())
    {
      var transactionJson = JsonConvert.SerializeObject(contents);

      HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
      request.Headers.Add("Authorization", $"Bearer {AUTH_TOKEN}");
      request.Content = new StringContent(transactionJson, Encoding.UTF8, "application/json");

      var httpResponse = await client.SendAsync(request);
      var data = await httpResponse.Content.ReadAsStringAsync();
      response = JsonConvert.DeserializeObject(data);
    }
  }
  catch (Exception exc)
  {
    throw exc;
  }

  return response;
}