Custom Form (Hosted Fields)

Step 1: Start Transaction

Advantages to using Custom Form

  • You have full control of placement
  • You have full UI/UX control
  • We support custom back-end HTML/CSS (Is this a problem? Please connect with an Integration Specialist for guidance.)
  • Works for card present and card not present solutions

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 on the client-side 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.

Basic Flow of Hosted Fields

Hosted fields works by appending iframe elements to container elements, such as div elements, on your form. The iframes display input fields hosted from our servers that will collect sensitive cardholder data. There are hosted fields for these data elements for credit card transactions:

  • Credit card number
  • Expiration date
  • Card security code

And these data elements for ACH transactions:

  • Account number
  • Routing number
  • Account holder name

Here are the steps:

  1. Your page loads with <div> elements in your payment form that will serve as containers for the hosted fields. For example,
    <div id="cardNumberContainer"></div> would act as a container for the iframe that contains the credit card hosted field.
  2. Your page includes a reference to the hosted fields assets javascript file in a script tag:
    <script src="assets_url/cip-hosted-fields.js"></script>
    When this assets file loads, it will expose a window.emergepayFormFields object.
  3. The javascript on your page should execute the following tasks once the page and javascript assets are fully loaded. We
    recommend wrapping these tasks in the window.onload callback or using $(document).ready() if you are
    using jquery.
  • Make a call to your backend to retrieve an emergepay transaction token (the getToken function in the code sample below
    is an example of this step).
  • Once you retrieve the token, configure the emergepayFormFields object and set the result to a variable so you can make a method call
    later, ie var hosted = emergepayFormFields.init(). The init function takes one argument, which is a configuration
    object. The call signature for the function is referenced in the code sample below. In the fieldSetUp property, you must
    include the id attribute of each container div in your form. When the emergepayFormFields object is initialized, we append an
    iframe as a child to each element referenced by id in the fieldSetUp property. These iframes are what pull down and
    display the hosted fields. So in the example div in step 1., we would attach the form field for the credit card number to the
    div with the id of “cardNumberContainer”.
  1. Attach a listener to the submit event on your payment form that calls hosted.process() when the form submits. This will
    initiate a background javascript process where we extract the values from the hosted fields and send them back to our
    servers, and then process the transaction request.
  2. Depending on the result of the transaction, we call either the success or failure callback you passed into your configuration
    object when calling emergepayFormFields.init().

That’s it. The code sample below gives you the code you need to implement this functionality.

Field Styling

Styling form fields can be done in your merchant configuration or on a per-field per-transaction basis.

An example of per-field styling can be seen in the code sample below in the styles object under each field in fieldSetUp. Any CSS property applicable to the input element is valid. A reference for the available CSS properties can be found on the MDN Web Docs CSS Reference page.

Note: if any styles are set via merchant configuration, the styles set in the styles object under each field will override them.

<!-- These are the elements that the fields will be appended to -->
<div>
  <!-- Elements that fields will be appended to for credit card transactions -->
  <div id="cardNumberContainer"></div>
  <div id="expirationDateContainer"></div>
  <div id="securityCodeContainer"></div>
  <!-- Elements that fields will be appended to for ACH transactions -->
  <div id="accountNumberContainer"></div>
  <div id="routingNumberContainer"></div>
  <div id="accountHolderNameContainer"></div>
  <!-- The hosted field for displaying the transaction amount is common for all transaction types -->	    
  <div id="amountContainer"></div>
  <button id="payBtn">Pay</button>
</div>


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

<!-- 
    After the script has loaded you will have access to the `window.emergepayFormFields` object. 
    This object has two public methods: `init()` and `process()`.
-->

<!-- Use the emergepay library -->
<script>
    $(document).ready(function () {
        getToken().then(function(transactionToken) {
            // Initialize the hosted fields
            var hosted = emergepayFormFields.init({
                // (required) Used to set up each field
                transactionToken: transactionToken,
                // (required) The type of transaction to run
                transactionType: "CreditSale",
                // (optional) Configure which fields to use and the id's of the elements to append each field to
                fieldSetUp: {
                    // These fields are valid for credit card transactions
                    cardNumber: {
                        appendToSelector: "cardNumberContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: { "background-color": "blue" }
                    },
                    cardExpirationDate: {
                        appendToSelector: "expirationDateContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: { "border": "1px solid red" }
                    },
                    cardSecurityCode: {
                        appendToSelector: "securityCodeContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: {}
                    },
                    // These fields are valid for ACH transactions
                    accountNumber: {
                        appendToSelector: "accountNumberContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: {}
                    },
                    routingNumber: {
                        appendToSelector: "routingNumberContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: {}
                    },
                    accountHolderName: {
                        appendToSelector: "accountHolderNameContainer",
                        useField: true,
                        // optional, automatically sets the height of the iframe to the height of the
                        // contents within the iframe. Useful when using the styles object
                        autoIframeHeight: true,
                        // optional, see styles section above for more information
                        styles: {}
                    },
                    // These fields are valid for all transaction types
                    totalAmount: {
                        useField: false
                    },
                    externalTranId: { 
                        useField: false
                    }
                },
                // (optional) If there is a validation error for a field, the styles set in this object will be applied to the field
                fieldErrorStyles: {
                    "border": "none",
                    "box-shadow": "0px 0px 4px 1px red"
                },
                // (optional) This callback function will be called when there is a validation error for a field.
                onFieldError: function (data) {
                    console.log(data);
                },
                // (optional) This callback function will be called when a field validation error has been cleared.
                onFieldErrorCleared: function (data) {
                    console.log(data);
                },
                // (optional) This callback function will be called when all of the requested fields have loaded
                // and are ready to accept user input. This can be useful for things like toggling the status
                // of loading indicators or ignoring clicks on a button until all of the fields are fully loaded
                onFieldsLoaded: function() {
                    console.log('All fields loaded');
                },
                // (optional) Callback function that gets called after a successful transaction
                onTransactionSuccess: function (approvalData) {
                    console.log('approvalData', approvalData);
                    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('failureData', failureData);
                },
                // (optional) Callback function that gets called after the user enters the first 6 digits of their card number.
                // This can be useful for showing a card brand icon to the user, or for determining if the card entered 
                // is a credit card or a debit card.
                onBinChange: function(binData) {
                  console.log('bin', binData.bin);
                  console.log('card type', binData.cardType);
                }
            });

            $('#payBtn').on("click", function (event) {
                event.preventDefault();
                //run the transaction if all fields are valid
                hosted.process();
            });
        });
    });

    // 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 sample code can be used to implement 
a polling model for fetching 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);
<?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 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;
});
<?php

//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 provided 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"}

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 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.
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.

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”.

Client-side only

After setting up tokenized transactions on your server, you will now need to retrieve tokens client-side and use it to interact with the device.

Device UI

The interface for handling device transactions is entirely up to you. We provide the following endpoints to interact with emergepay when using devices, at a minimum you will need to make a request to initiate the device endpoint.

Device URLs

Sandbox Endpoint

URL Type URL
device https://api.emergepay-sandbox.chargeitpro.com/device/v1/

 

Production Endpoint

URL Type URL
device https://api.emergepay.chargeitpro.com/device/v1/

Initiate Device

This endpoint will start the transaction on the device
`PUT {device_url}/deviceTransactions/{transactionToken}`

Retrieve Results

This endpoint can be used to poll for results
`GET {device_url}/deviceTransactions/{transactionToken}`

Cancel Transaction

This endpoint will cancel the transaction on the device
`DELETE {device_url}/deviceTransactions/{transactionToken}`

Convert to Manual Entry

This endpoint will cancel the transaction on the device, and put the transaction into a state that accepts manual entry via the emergepay form fields. Refer to Step 2 for more information on how to load the fields.

`PATCH {device_url}/deviceTransactions/{transactionToken}/convertToKeyed`

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.

After you initiate the device by making a request to the endpoint listed above, you can then launch our simulated device. The simulated device is a browser-based device that can be accessed by navigating to a new tab with the following url: {environmentUrl}/transactions/simulatedDevice?xtoken={transactionToken}, where {transactionToken} is the transaction token received from Step 1.

The simulated device allows you to 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 retrieve the results using the Retrieve Results endpoint listed above and handle the transaction response in your custom UI to complete the flow of the transaction.

Input fields for RequestSignature

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

Signature review not available with Hosted Fields

The RequestSignature feature on the Hosted Fields integration operates differently from our other integrations. A user will not be able to review a customer’s signature before it is sent to the Point of Sale.

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: "hostedFields",
        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: "hostedFields",
        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' => 'hostedFields',
    '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 = "hostedFields",
      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;
}