Simple Form (Modal)

Step 1: Start Transaction

Merchant server only

Environment & Asset URLs

Sandbox Account

URL Type URL
environment https://api.emergepay-sandbox.chargeitpro.com/virtualterminal/v1
assets https://assets.emergepay-sandbox.chargeitpro.com

 

Production Account

URL Type URL
environment https://api.emergepay.chargeitpro.com/virtualterminal/v1
assets https://assets.emergepay.chargeitpro.com

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 an integration specialist for more information.

<!-- 
Load emergepay modal 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-modal.js"></script>

<!--
After the script has loaded you will have access to the `window.emergepay` object. 
This object has three public methods: `open()`, `close()`, and `init()`.
-->

<!-- Use emergepay library -->


<script>
    window.onload = function() {
        // Initialize emergepay modal (not required, but makes things load faster)
        emergepay.init();

        // Set up event listener on Pay With Card button
        document.getElementById('cip-pay-btn').addEventListener('click', function(e) {
            e.preventDefault();
            
            // Get a transactionToken serverside
            getToken()
            .then(function(transactionToken) {
                // Set up and open the payment modal
                emergepay.open({
                    // (required) Used to set up the modal
                    transactionToken: transactionToken,
                    // (optional) Callback function that gets called after a successful transaction
                    onTransactionSuccess: function(approvalData) {
                        console.log("Approval Data", approvalData);
                        emergepay.close();
                        location = "https://gravitypayments.com";
                    },
                    // (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);
                    },
                    // (optional) Callback function that gets called after a user clicks the close button on the modal
                    onTransactionCancel: function () {
                        console.log("transaction cancelled!");
                    }
                });
            });
        });
    };

    // This function makes a call to your server to get a transaction token
    function getToken() {
        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>

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.

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 Gravity Payments
    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 Gravity Payments
    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);
$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 Gravity Payments
    $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 Gravity Payments
  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;
});
//Configure your oid and auth token. These are supplied by Gravity Payments.
//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 Gravity Payments.
//Note: Make sure you set this before attempting to retrieve transaction results.
$externalTransactionId = '';

//Configure the environmentUrl. This is supplied by Gravity Payments.
$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 Gravity Payments 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;
}

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":"","createdOn":"2022-04-18T20:52:50.370Z","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":"","createdOn":"2022-04-18T20:52:50.370Z","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":"","createdOn":"2022-04-18T20:52:50.370Z","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"}

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");
    });
//Configure your oid and auth token. These are supplied by Gravity Payments.
//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 Gravity Payments.
//Note: Make sure you set this before attempting to retrieve transaction results.
$externalTransactionId = 'your_external_transaction_id';

//Configure the environmentUrl. This is provided by Gravity Payments.
$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 Gravity Payments 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
    • Does not support the tip_amount or prompt_tip fields in the start transaction request
  • RequestSignature
  • CreditSaveCard
    • Only supported for Clover Flex and Mini devices

Transaction Types Not Available

  • ACHSale
  • ACHReturn

Additional transaction input fields required

NameDetailsRequiredDescription
device_nameType: string
Max length: 50
YesThe name of the device to use for the transaction. Case sensitive and generally provided by Gravity.
prompt_tipType: 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. If "prompt_tip" is set to "true", "tip_amount" must be omitted or set to "0.00". The fields cannot work in tandem.
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.

Testing Without a Physical Device

Want to test device-based transactions without a physical device? Our simulated device is a great way to do quick device-based testing with your integration. To use it, simply supply SimulatedDevice in the device_name field.

When the emergepay modal opens from Step 2, a link to open the simulated device will display just below the transaction details. Clicking the link will open our simulated device in a new browser tab, where you can click through the transaction options that you want to simulate for the transaction type supplied in Step 1. After confirming the transaction options to simulate, you will see a transaction result screen on the simulated device. You can then navigate back to the browser tab that the emergepay modal is open in to see the transaction result screen on the emergepay UI to proceed with your testing.

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. Accepted characters are "a" to "z", "A" to "Z", "0" to "9", ".", "_", "-", and space characters.
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 Gravity Payments.
//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 = [
  'transactionData' => [
    'transactionType' => 'RequestSignature',
    'method' => 'modal',
    'fields' => [
      ['id' => 'external_tran_id', 'value' => GUID()],
      ['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 Gravity Payments 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;
}