Basic Integration

Custom Integration

Just want to create an online Merchant Application?

Skip to learn how to create a Merchant Application.

In this tutorial we will guide you through the process of integrating with the Marketplace API and then how to create your own Marketplace. We will walk you through step-by-step but feel free to skip forward. You can also use our fully functional Demo Marketplace as a reference throughout this tutorial.

To get started, you must request access to the Marketplace developer sandbox environment. We assume you have a company website that you would like to add Marketplace and the online Merchant Application to. Your Marketplace can also be a standalone site - up to you. Refer to the Demo Marketplace for the standalone experience.

What APIs are available for use?

We provide developers with a detailed API documentation of all available Marketplace APIs for products and the Merchant Application.

  1. Request Access to Sandbox

Next: Set up your developer environment.

Skip to: Create Marketplace of commerce products or create online Merchant Application for processing payments if you don’t want to sell any commerce products.

Environment Setup

Node Setup

What is Node?

Node is an executable version of Chrome’s V8 JavaScript engine that allows you to write JavaScript code on the server.

Why Node?

Various technologies and frameworks exist for developing backend applications. We chose Node for this tutorial because of its ease of use to setup and install.

This section assumes you have not used Node.js (Node) before and do not have Node installed on your system. Feel free to skip to Authentication if you are comfortable.

In order to integrate the First Data API into a Marketplace app using Node, we will need to properly configure our developer environment. In this section, we’re going to take a look at setting up a Node Developer Environment.

In this tutorial, we are going to set up the necessary tools to get started using npm and a Node Developer Environment).

What is npm?

Node Package Manager, commonly referred to as npm, is the default dependency manager for all Node projects.

Setting up the Environment Locally

Download the repo

Download the FD Marketplace sample app on GitHub or view it live here.

To begin setting up Node, navigate to the official Node website and select the latest version of Node. The Node website should automatically detect which operating system your computer is running. Node typically offers two versions for download but we suggest you that you download the version Node recommends for you.

When the download finishes, click on the file to open and run. Continue through the Node installer, accept the terms if you have read them and agree, and then install Node on your system.

Your version of Node may be different than the version displayed in the screenshots. Node is updated frequently, so please make sure you download the latest version.

Excellent! You have successfully installed Node.js on your machine. The Node installer also includes the Node Package Manager (npm) which helps install and manage dependencies.

NOTE: Not sure what a dependency is? A dependency is a third party file, package, or resource you include in your project to extend its capabilities. Node has a vibrant developer community. As a result, it has thousands of dependencies available for use in your projects via the npm website (accessible at npmjs.com).

We’ll be using npm momentarily but before that, we need to discuss a few dependencies we’ll be using.

What is Express.js?

Express.js is a powerful web framework which helps with setting up routes for npm projects.

In order to get our environment up and running, we’re going to use a dependency called Express.js. Express is a module that helps us build web servers in Node.

In addition, we’re also going to be using a module called body-parser to parse, or read, incoming requests from our server. If you’re not sure what any of this means quite yet, don’t worry! We’ll be explaining everything in this tutorial.

Application Setup

Our Demo Marketplace is open sourced and free to download on GitHub. Throughout this tutorial, we’ll break down how this app works and the process involved in extending it to fit your needs. Feel free at any time to customize this app accordingly.

Please make sure you have cloned or downloaded the Demo Marketplace projects from GitHub before proceeding.

Now that you have Node (and npm which is packaged with Node) set up on your local machine, it is time to take a look at the Demo Marketplace App.

Using the terminal app, type cd (also known as change directory) and press the space key. Then drag the folder you just downloaded from GitHub into the terminal window. You should see something similar to the screenshot below.

Please note that your terminal may look different and the path may also be different from what is displayed in the screenshot.

cd ~/Desktop/Marketplace-Demo

We’re going to install all the dependencies required for this app. To do so, type npm install --save to install and save all the dependencies.

npm install --save

This command retrieves a list of packages from a file called package.json. The npm install command then installs the relevant packages accordingly so your computer can compile and run the app.

If you don’t see any errors, you’re good to go.

Next, you’ll need to modify the config/default.json file with your new sandbox credentials (the same credentials you received via email). To do so, go to the root of the project folder you downloaded and navigate to the config directory. Then, open up the default.json file in a text editor of your choosing (we recommend Sublime Text or Atom, but feel free to use any editor you like).

Make sure to replace the variables (denoted by the xxxxx-xxxxx-xxxxxx-xxxxx-xxxxx text) with your keys.

Sandbox

If you have not done so already, please request credentials from the sandbox and then replace the values in the config/default.json file with the credentials you received via email.

Now, type the npm start to start your server! Click on the below link to view your app.

Lightning Implementation

Use the button below to auto deploy your app to the Heroku cloud! You will need to add your username secret, and base url for this app to work.

View Lightning Options

  1. View my App

Congratulations, you’ve successfully configured your local environment!

What if I See Errors?

If you see errors, please visit npm’s official website to troubleshoot.


Next Steps

In this section, we set up a Node.js developer environment on our local machine, downloaded the sample Demo App from GitHub, and built and ran that app. As you can see, setting up Node is quite straightforward and easy.

Next: Cool! Teach me how to authenticate.

Skip to: Create online Merchant Application for processing payments if you don’t want to sell any commerce products.

Authentication

Why do we Require Authentication?

In one word: security. Numerous high level credit card breaches have increased the need for more advanced cryptography standards to protect credit card holders. The Payment Card Industry Data Security Standard (PCI DSS) - an information security standard used by all the major credit card networks - requires merchants to encrypt specific card holder information. Using HMAC Authentication is a standard method of protecting this sensitive information.

Now that you have your environment set up, let’s take a look at authentication. In order to properly access and make calls to the First Data Marketplace APIs, you will need to authenticate your requests. To do so, you’ll need to generate HMAC authentication.

HMAC authentication, also known as hash-based message authentication code, is a cryptographic authentication scheme involving a hash function used in combination with a secret key.

To try any of the code in this tutorial, you can use your credentials for our Sandbox, sent to you via email. Don’t have credentials?

  1. Request Access to Sandbox

Below is a list of the following authorization headers you are expected to send with each API request:

What is HMAC Authentication?

Hash-based Message Authentication Code (HMAC) is a message authentication code that uses a cryptographic key in conjunction with a hash function. HMAC provides both the server and client each with a public and private key. While the public key is known, the private key is known only to that specific server and that specific client.

Parameter Description
username The username of the credential received in email.
algorithm Digital signature algorithm used to create signature. First Data only supports HMAC-SHA1.
headers List of header names, separated by a single space character, used to sign the request.
signature Base64 encoded digital signature generated by the client.

Please note that a valid time stamp (date) is mandatory for authentication.

Authorization in Action

With this information in mind, navigate to your Demo Marketplace folder and open the server.js file in a text editor of your choosing.

Below is the code we used to generate HMAC Authorization and authenticate our app with the First Data Marketplace API. As you can see, we’ve created a function called getAuthenticationHeaders() and use the format defined in the above table to authenticate.

var getAuthenticationHeaders = function () {
  var date = new Date().toUTCString();
  var stringToSign = 'date: ' + date.trim();
  var encodedSignature = crypto.createHmac("sha1", secret).update(stringToSign).digest("base64");
  var hmacAuth = 'hmac username="' + username + '",algorithm="hmac-sha1",headers="date",signature="' + encodedSignature + '"';
  return {
    'date': date,
    'Authorization': hmacAuth
  }
}

The server.js file uses Node’s crypto module to generate a hash and create the HMAC. To use crypto, we included the following code at the top of the file (we have already done this in server.js)

Learn more about hash-based message authentication code (HMAC) here.

const crypto = require('crypto');

What is Crypto?

Crypto is a Node module that provides cryptographic functionality such as HMAC, OpenSSL hash, etc. You can learn more about crypto here.

Example Request

Now that we have authenticated our API calls to the First Data Marketplace API, we can make a request using the getAuthenticationHeaders() function defined above.

Below is an example Node GET request that lets us retrieve FAQs on a particular product.

app.get('/marketplace/v1/products/:pid/faq/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/faq/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

Running this code with a valid productId will return JSON structured like the data shown below. For now, don’t worry about actually running this code. We’ll discuss using this function and more later in this tutorial.

[
  {
    "header": "Printer Paper Sizes?",
    "shortAnswer": "The Clover Station Printer takes 3 1/8” X 230’ thermal paper rolls.",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57933826",
    "sortId": 1
  },
  {
    "header": "Which weight scales are supported by Clover?",
    "shortAnswer": "Clover supports the CAS SW-20 Weight Scale. In order to connect the scale to your Clover Station or Clover Mini, you will need a custom cable that comes bundled with the scale when purchased from your Clover provider.",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=55378004",
    "sortId": 2
  },
  {
    "header": "Does Clover support layaway?",
    "shortAnswer": "Clover does not currently support layaway directly on Register app register-app-icon. Third party apps may support layaway in the future.",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57212991",
    "sortId": 3
  },
  {
    "header": "Does Clover integrate with E-commerce?",
    "shortAnswer": "Our third party apps E-commerce solutions for you...",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57212992",
    "sortId": 4
  },
  {
    "header": "Does Clover support Telecheck?",
    "shortAnswer": "First Data has launched a Telecheck app on the Clover platform. Once the Telecheck app has been downloaded and installed on your Clover device, you can start accepting payments in Telecheck.",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57212993",
    "sortId": 5
  },
  {
    "header": "Will I be able to accept HSA or FSA from my customers?",
    "shortAnswer": "HSA/FSA cards are debit cards (Visa/Mastercard) that typically have associated customer pins. The cards themselves have no extra level of data associated with them but because they are associated as HSA/FSA to the networks, in ord...",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57212994",
    "sortId": 6
  },
  {
    "header": "How do I change my batch closeout time?",
    "shortAnswer": "If you are on autoclose and you would like to change your batch closeout time, please contact customer support with your new closeout time request.",
    "url": "https://gyftteam.atlassian.net/wiki/pages/viewpage.action?pageId=57212995",
    "sortId": 7
  }
]

The above given example, retrieves FAQ’s for a specific product. However, as part of the Marketplace Demo application, all the server calls, are grouped together in app.all express js call, with “/marketplace/*” as route and a callback function with “req” and “res” as parameters. This call acts as a service end point proxy for any server call that happens inside Marketplace Demo application.

Below is the code snippet for the same.

/**
 * POST and GET service end-point proxy
 */
app.all('/marketplace/*', function(req, res) {
  var options = {
    method: req.method,
    url: kongUrl + req.originalUrl,
    headers: getAuthenticationHeaders()
  };
  if (req.method == 'POST') {
    options['json'] = req.body;
    options['content-type'] = 'application/json';
  }

  request(options, function(error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

What is a productId?

A productId is the unique code that represents each product. We’ll talk about productIds and the FAQ endpoint later in this tutorial.


Next Steps

In this section, we discussed authentication, why First Data requires authentication, and how to authenticate our app to the First Data Marketplace API. In the next section, we’ll take an even closer look at a sample request.

Next: Cool! Teach me more about authentication.

Skip to: Code App if you want to get down to business writing your app.

Breakdown

Now that we’ve discussed the setup required in the getAuthenticationHeaders() function and how basic HMAC authentication works in our demo app, let’s take a more detailed look at the code that powers server.js, the primary file that powers the Demo Marketplace’s backend logic.

In this section, we’ll explore how to make a request to the API using HMAC authentication and return the JSON sent from the First Data Marketplace API for use on the client side.

Let’s start by discussing the first code snippet. This code can be found in the beginning section of the server.js file.

Click here to see the entire server.js file.

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var request = require('request');
var crypto = require('crypto');
var config = require('config');

/**
 * load configuration from config/default.json
 */
var APIUrl = process.env.APP_API_URL ? process.env.APP_API_URL : config.get('API.url');
var username = process.env.APP_API_USERNAME ? process.env.APP_API_USERNAME : config.get('API.username')
var secret = process.env.APP_API_SECRET ? process.env.APP_API_SECRET : config.get('API.secret');
var port = process.env.APP_PORT ? process.env.APP_PORT : config.get('port');

// load web app
app.use('/web', express.static(__dirname + '/web'));

app.use( bodyParser.json() );       // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
  extended: true
}));

app.use(express.static('web'));


app.listen(config.get('port'), function () {
  console.log('listening on port ' + config.get('port'));
});

As you can see, the first several lines set up the Express app that powers the site. We have designated the web directory as the primary static folder for this app. Additionally, this app uses body-parser to handle incoming post requests.

Now, let’s review the routes section. Below are the sample routes for each section of this app. We will discuss the particular Marketplace APIs later in this tutorial.

What are Routes?

Routes are paths such as GET or POST requests that define the structure of our app.

You can learn about any Node module on npm’s official website.

/**
 * prepare auth headers for API server
 * @returns {{date: string, Authorization: string}}
 */
var getAuthenticationHeaders = function () {
  var date = new Date().toUTCString();
  var stringToSign = 'date: ' + date.trim();
  var encodedSignature = crypto.createHmac("sha1", secret).update(stringToSign).digest("base64");
  var hmacAuth = 'hmac username="' + username + '",algorithm="hmac-sha1",headers="date",signature="' + encodedSignature + '"';
  return {
    'date': date,
    'Authorization': hmacAuth
  }
}

/**
 * GET service /marketplace/v1/categories
 * get list of categories
 */
app.get('/marketplace/v1/categories', function(req, res) {
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/categories',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products
 * get list of products
 */
app.get('/marketplace/v1/products', function(req, res) {

  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});


/**
 * GET service /marketplace/v1/products/:pid/details/
 * get product details
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/details/', function(req, res) {

  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/details/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/features/
 * get product features
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/features/', function(req, res) {

  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/features/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/specs/
 * Get product specifications
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/specs/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/specs/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/recommended/
 * Get recommended products for product
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/recommended/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/recommended/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/includes/
 * Get included products
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/includes/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/includes/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/options/
 * Get options products like visa/master card
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/options/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/options/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/products/:pid/faq/
 * Get product FAQ
 * @param pid
 */
app.get('/marketplace/v1/products/:pid/faq/', function(req, res) {
  var pid = req.params.pid;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/products/' + pid + '/faq/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/categories/:categoryName/industries/
 * Get MCC codes
 * @param categoryName
 */
app.get('/marketplace/v1/categories/:categoryName/industries/', function(req, res) {
  var categoryName = req.params.categoryName;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/categories/' + categoryName + '/industries/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/categories/:categoryName/industries/:industryDescription/merchantcategorycodes/
 * Get MCC types
 * @param categoryName
 * @param industryDescription
 */
app.get('/marketplace/v1/categories/:categoryName/industries/:industryDescription/merchantcategorycodes/', function(req, res) {
  var categoryName = req.params.categoryName;
  var industryDescription = req.params.industryDescription;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/categories/' + categoryName + '/industries/' + industryDescription + '/merchantcategorycodes/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * GET service /marketplace/v1/contracts/:orderId/agreement/
 * Get contact greement information
 * @param orderId
 */
app.get('/marketplace/v1/contracts/:orderId/agreement/', function(req, res) {
  var orderId = req.params.orderId;
  var options = {
    method: 'GET',
    url: APIUrl + 'marketplace/v1/contracts/' + orderId + '/agreement/',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/cart/validate
 * validate cart
 */
app.post('/marketplace/v1/cart/validate', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/cart/validate',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/application/submit/
 * Sign merchant application
 */
app.post('/marketplace/v1/application/submit/', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/application/submit',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/pricing/equipment
 * Get Equipment pricing
 */
app.post('/marketplace/v1/pricing/equipment', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/pricing/equipment',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/pricing/global
 * Get Global pricing
 */
app.post('/marketplace/v1/pricing/global', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/pricing/global',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/pricing/acquiring
 * Get Acquiring pricing
 */
app.post('/marketplace/v1/pricing/acquiring', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/pricing/acquiring',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/application/checkout
 * Checkout order
 */
app.post('/marketplace/v1/application/checkout', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/application/checkout',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

/**
 * POST service /marketplace/v1/application/update
 * Submit merchant application
 */
app.post('/marketplace/v1/application/update', function(req, res) {
  var body = req.body;
  var options = {
    method: 'POST',
    url: APIUrl + 'marketplace/v1/application/update',
    json: body,
    "content-type": 'application/json',
    headers:getAuthenticationHeaders()
  };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
  });
});

It is critical that you send the HMAC headers in every request.

Let’s take a look at the first example route (GET service /marketplace/v1/categories). This route makes a GET request to the First Data Marketplace API and returns the relevant JSON. It sends the headers returned from the getAuthenticationHeaders() function in the request for authentication.

Finally, each request uses Node’s res.send() function to return the JSON received from the First Data APIs. This data is then be used in the frontend app.


Next Steps

In this section, we look a basic look at the server.js file that powers our Demo Marketplace. You should now have a basic understanding on how to use a backend framework (such as Node) to make requests to the First Data Marketplace APIs and return JSON using HMAC authentication.

In the next section, we’ll take a look at coding our app. See you then!

Next: Awesome, take me to Code App!

Code App

Angular Used

This tutorial assumes you have experience with Angular JS.

What is fd.js?

Many of our angular methods are defined in a file called fd.js. You may want to reference this file from time to time to see complete method declarations.

In this section we will take an in-depth look at the frontend code that powers our Demo Marketplace. By the end of this tutorial, you will have a working understanding of the technology that powers our frontend.

In the interim, please take look at our demo app here and become acquainted with the app’s layout.

In this chapter, each section is divided in two sections: HTML and Angular JS code. We’ve done this for simplicity and readability and hope this makes it easy for you to comprehend and understand the app. It is strongly recommended that you not only follow along the code snippets, but also deploy a working app to either localhost or your own server as described in the Authentication and Environment Setup sections.

Customization

If you would like to modify your marketplace’s theme/look & feel, you can do so by navigating to the `web/stylesheets` directory and modifying one of the many css files there.

You can find the corresponding HTML for every page inside the views and templates directories. We’ve also included snippets of the HTML and JavaScript code throughout this tutorial for ease of use.

Want to see the full code in action while following along this tutorial? Download the First Data Marketplace sample app on GitHub.


Lightning Implementation

We realize that setting up a server locally is often not as easy as deploying a production environment. That’s why we build Lightning Implementation to assist.

Use the buttons below to trigger our “Lightning Implementation” and set up your app on your own servers within minutes. We currently support popular cloud environments such as AWS, Azure and Heroku with more coming soon.

You will need to add your SANDBOX_URL (the URL you received in the email), API_KEY (the key you received in the email), API_SECRET (the secret you received in the email) and the APP_PORT (this can be any integer you like, but we recommend 3000, 8081, or 4040) as environment variables.

Deployment is fast, easy and usually takes under 2 minutes to get a live, running version of your own app on your servers!

Deploy to AWS Deploy

Next Steps

In this section we introduced the concepts we’ll be discussing in this chapter. In the next section, we’ll jump into coding the Categories section of our app!

Next: Display Categories in your Marketplace

Marketplace For Sales Teams

Have questions about our APIs?

Check out our detailed API documentation.

First Data allows partners to sell First Data’s commerce products, such as terminals, POS systems and other commerce software while offering an online Merchant Application to sign up merchants for payment processing. This solution is called Marketplace. Marketplace is a PCI and PII compliant platform leveraging the latest technologies for tokenization and encryption.

What is a “Marketplace”?

First Data makes it easy for you to sign up and onboard your merchants. Our solution allows you to offer merchants the ability to purchase payment products and sign up for a merchant account quickly and easily. We call this Marketplace.

We offer two ways for our partners to use Marketplace:

  1. Custom Integration Create your own app with a custom experience, coding to our APIs.
  2. Hosted Marketplace (Coming Soon) Hosted experience you can customize to your own brand.

Categories

Overview

API: GET Categories

Check out the detailed API documentation of the GET Categories API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

The first step in setting up our Marketplace app is to display a list of categories. We’ll want to display the relevant categories that our products are grouped by for organizational purposes.

To do this, we’ll make requests to the First Data Marketplace API’s GET Categories endpoint and save the relevant response data.

In this section, we’re going to discuss the HTML and JavaScript code involved in making this request.

Example user interface displaying Categories Example user interface displaying Categories

Frontend example

NOTE: You can find the corresponding HTML for this page inside the views directory. We’ve also included snippets of the HTML and JavaScript throughout this tutorial.

Below is the sample Angular HTML view we used to display categories in the Demo Marketplace. This code uses Angular’s ng-repeat directive to loop through the categories returned from the GET Categories API endpoint.

HTML

This code can be found in
view/index.html.

<section id="shop-businesstypes" class="align-center">
  <div class="container">
    <h1>Select business type</h1>
    <p class="subhead">First Data offers ready-to-go bundles that are perfectly suited for your type of business.</p>
    <div ng-repeat="item in categories" class="business-type column-3">
      <a style="background:url({{item.imageURL ? item.imageURL : placeholderImageUrl}})" ng-click="changeCategory(item)" href="javascript:;"><span>{{item.description}}</span></a>
     </div>
  </div>
</section>

Now that we’ve taken a look at the sample HTML, let’s discuss the JavaScript. In the below code snippet, we make a call to the GET Categories API endpoint using the fdService.getCategories() function and then store the response data (JSON) in $scope for later use in our app. We then display the content on the screen using the above HTML view.

What is $scope?

Google defines $scope as an “object that refers to the application model.” In short it is a globally accessible object that can be accessed inside HTML views to display data on screen.

JavaScript

This code can be found in
js/index.js.

/**
 * Index Controller
 */
app.controller('IndexCtrl', ['$scope', '$rootScope', '$filter', '$location', '$anchorScroll', '$timeout', 'fdService',
    function ($scope, $rootScope, $filter, $location, $anchorScroll, $timeout, fdService) {

  /**
   * Init function
   * @private
   */
  var _init = function(){

    $rootScope.wrapperClass = 'home';
    $rootScope.body_id = 'shop';
    $scope.categories = [];

    fdService.getCategories()
      .success(function(data, status, headers, config) {
        $scope.categories = data;
      })
      .error(function(data, status, headers, config) {
        console.log('error')
      });
  };

  /**
   * Move to anchor
   * @param {string} ancor
   */
  $scope.gotoAnchor = function(anc){
    $timeout(function() {
      $location.hash(anc);
      $anchorScroll();
    });
  };

  /**
   * Change active category
   * @param {Object} category
   */
  $scope.changeCategory = function(category){
    fdService.storeCategoryInSession(category);
    $location.path('/products/c');
  };

  ///////////////// MAIN ////////////////////////////////

  _init();
}]);

Next Steps

In this section we discussed the GET Categories endpoint and how to display categories in our app. In the next section, we’ll discuss how to display products.

Next: Display products in your Marketplace

Product List

Overview

API: GET Products

Check out the detailed API documentation of the GET Products API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Now that we’ve set up and displayed Categories in our sample app, let’s discus the process of displaying a product catalog.

Our API provides First Data-curated products, such as Clover products, partner payment terminals, partner software solutions, hardware accessories and more.

In our Demo Marketplace we display the list of products for each category. Based on "categoryIds": [] such as 100, 101, 102 where the numbers represent the id attribute of the Category.

You can further filter the list of products based on various parameters such as:

In this section, we’ll set up a basic user interface as the one below.

Example user interface for displaying products Example user interface displaying Products

Frontend example

The process of displaying a product catalog is quite similar to how we displayed the categories in the previous section.

First, we will need to make a GET request to the GET Products API endpoint, retrieve the relevant data (JSON) and store it in $scope.

In the above view, we use Angular’s ng-repeat directive to loop through the response data and display it on screen.

HTML

This code can be found in
view/products.html.

<div id="search">
  <div class="container">
    <div class="column-12">
      <form id="products-filters" autocomplete="off">

        <span class="icon"><i class="fa fa-2x fa-search"></i></span>
        <input id="search-products"  type="text" placeholder="i.e. Barcode Scanner" ng-model="keyword" ng-change="search()" />
        <div class="inline-block">
          <select id="categoryfilter" ng-disabled="categoryDisabled" class="js-example-basic-multiple" multiple="multiple" use-select2 placeholder="All Business Categories" ng-model="businessCategory" ng-change="changeCategory()" ng-options="c.name for c in categories track by c.id.toString()"></select>
        </div>
      </form>
    </div>
  </div>
</div>
<div class="main-content">
 <section id="products-main">
   <div class="container">

     <div class="column-12" ng-show="productContentType == 'recommended'">
       <h3>Recommended Products For <strong>{{recommendedProductName}}</strong></h3>
       <p class="subhead" ng-show="!isRecommendedCallDone">Loading....</p>
       <div class="shop-product featured column-3" ng-repeat="p in recommendedBundles track by $index ">
         <a ng-href="#/product/{{p.productId}}">
           <img ng-src="{{ProductThumbImg(p.imageUrls)}}">
         </a>
         <p>{{p.productName}}</p>
         <a class="link-blue" ng-href="#/product/{{p.productId}}">View Details</a>
       </div>
     </div>

     <div class="column-12" ng-show="heroProds.length">
       <h3>Featured Products</h3>
       <p class="subhead">Currently featured products that may be of interest to you</p>
       <div class="shop-product featured column-3" ng-repeat="p in allProducts | filter:filterHero | filter:filterProd as heroProds track by $index ">
         <a ng-href="#/{{p.prod_url}}">
           <img ng-src="{{ProductThumbImg(p.imageUrls)}}">
         </a>
         <p>{{p.productName}}</p>
         <a class="link-blue" ng-href="#/{{p.prod_url}}">View Details</a>
       </div>
     </div>

     <div  style="clear:both;" id="allproducts">
        <div class="column-9">
          <h3>All Products</h3>
        </div>
      </div>
      <div class="column-12" infinite-scroll='loadMore()' infinite-scroll-distance='2'>
        <div class="shop-product hardware" ng-repeat="p in products | orderBy:sortbytag | filter:filterProd as prodToShow track by $index ">
          <a ng-href="#/{{p.prod_url}}">
            <img ng-src="{{ProductThumbImg(p.imageUrls)}}">
          </a>
          <p>{{p.productName | limitToEllipsis:45}}</p>
          <a class="link-blue" ng-href="#/{{p.prod_url}}">View Details</a>
        </div>
      </div>
    </div>
  </section>

</div><!-- end .content -->

JavaScript

This code can be found at
js/product.js.

Now that we have discussed the HTML, let’s talk about the JavaScript code that powers our view.

In the below code snippet, we make a call to the GET Products API and store the response data (JSON) in $scope. Then, using the products Controller (ProductsCtrl), we can display the content on screen for use in our HTML view discussed above.

/**
 * Products Controller
 */
app.controller('ProductsCtrl', ['$scope', '$rootScope', '$filter', '$location', '$routeParams', '$timeout', '$anchorScroll', '$window', 'fdService', 'CONST',
    function ($scope, $rootScope, $filter, $location, $routeParams, $timeout, $anchorScroll, $window, fdService, CONST) {

  /**
   * Init function
   * @private
   */
  var _init = function(){

    $rootScope.body_id = 'products';
    $scope.categoryDisabled = true;
    $scope.prodToShow = [];
    $scope.keyword = '';
    $scope.categoryId = null;
    $scope.categories = [];

    $scope.recommendedBundles = [];

    $scope.images = [];
    $scope.cimage = $rootScope.placeholderImageUrl;

    $scope.allProducts = [];
    $scope.products = [];

    // Get Categories
    fdService.getCategories()
      .success(function(data, status, headers, config) {
        $scope.categories = data;
        if ($routeParams.type){
          if ('c' == $routeParams.type) {
            $scope.categoryDisabled = true;
            var c = fdService.getCategoryFromSession();
            if (c) {
              $scope.category = c;
              $scope.businessCategory = [c];
              $timeout(function() {
                angular.element('#categoryfilter').trigger('change');
                $scope.loadMore();
              }, 1);
            } else {
              $scope.category = null;
            }
          } else if ('t' == $routeParams.type && $routeParams.typename) {
            $scope.productType = $routeParams.typename;

            $timeout(function() {
              $scope.loadMore();
            }, 1);
          } else if('recommended' == $routeParams.type){
            $scope.productContentType = $routeParams.type;
            $scope.isRecommendedCallDone = false;
            var pid = $routeParams.typename;
            fdService.getRecommendedBundles(pid)
              .success(function(data, status, headers, config) {
                $scope.recommendedBundles = data;
                $scope.isRecommendedCallDone = true;
              })
              .error(function(data, status, headers, config) {
                $scope.recommendedBundles = [];
                $scope.isRecommendedCallDone = true;
                console.log('error')
              });
          }
        }
      })
      .error(function(data, status, headers, config) {
        console.log('error')
      });

    // Get all products
    fdService.getAllProducts()
      .success(function(data, status, headers, config) {
        $scope.allProducts = [];

        for (var i in data){
          var p = data[i];
          if (p.productType.indexOf('FEE') != -1) {
            continue;
          }
          if (p.productWithOptions) {
            p.prod_url = 'family/' + p.productFamilyId;
          } else if ('ACQUIRING' == p.productType) {
            p.prod_url = 'processing/' + p.productId;
          } else {
            p.prod_url = 'product/' + p.productId;
          }
          $scope.allProducts.push(p);
        }

        $scope.generateAcData($scope.allProducts);

        $scope.loadMore();
      })
      .error(function(data, status, headers, config) {
        $scope.allProducts = [];
        $scope.generateAcData([]);
      });
  };

  /**
   * Change active category
   */
  $scope.changeCategory = function(){
    if(!$scope.$$phase) {
      $scope.$apply();
    }
    $scope.generateAcData($scope.allProducts);
    $scope.loadMore();
  };

  /**
   * search products
   */
  $scope.search = function(){
    if(!$scope.$$phase) {
      $scope.$apply();
    }
    $scope.loadMore();
  };

  /**
   * Sort products by tag filter
   * @param {Object} product
   * @return {number}
   */
  $scope.sortbytag = function(p){
    if (p['tags'] && p['tags'].indexOf('TOP 10') != -1) {
      return 0;
    }
    return 1;
  }

  /**
   * Filter featured products
   * @param {Object} product
   * @return {boolean}
   */
  $scope.filterHero = function(p){
    if (p['tags']) {
      if (p['tags'].indexOf('HOME') != -1) {
        return true;
      }
    }
    return false;
  };

  /**
   * Filter products
   * @param {Object} product
   * @return {boolean}
   */
  $scope.filterProd = function(p){

    var ret = true;
    if ($scope.productType) {
      if (p['productType'] == $scope.productType) {
        ret = true;
      } else {
        ret = false;
      }
    }
    if ($scope.businessCategory && $scope.businessCategory.length) {
      ret = false;
      if (p['categoryIds']) {
        for (var i = 0; i < $scope.businessCategory.length; i++) {
          if (p['categoryIds'].indexOf(parseInt($scope.businessCategory[i].id)) != -1) {
            ret = true;
            break;
          }
        }
      }
    }
    if (!$scope.keyword || !$scope.keyword.length || p.productName.toLowerCase().indexOf($scope.keyword.toLowerCase()) != -1) {
      ret = ret && true;
    } else {
      if (p['tags'] && p['tags'].indexOf($scope.keyword) != -1) {
        ret = ret && true;
      } else {
        ret = false;
      }
    }
    return ret;
  };

  /**
   * Generate autocomplete data
   * @param data
   * @return {Array}
   */
  $scope.generateAcData = function(data){

    var acData = [];

    for (var i in data){
      var p = data[i];
      var incl = true;
      if ($scope.businessCategory && $scope.businessCategory.length) {
        incl = false;
        if (p['categoryIds']) {
          for (var k = 0; k < $scope.businessCategory.length; k++) {
            if (p['categoryIds'].indexOf(parseInt($scope.businessCategory[k].id)) != -1) {
              incl = true
              break;
            }
          }
        }
      }
      if (!incl) {
        continue;
      }

      if (acData.indexOf(p.productName) == -1) {
        acData.push(p.productName);
      }
      for ( var k in p.tags) {
        if (acData.indexOf(p.tags[k]) == -1) {
          acData.push(p.tags[k]);
        }
      }
    }

    $("#search-products" ).autocomplete({
      delay: 0,
      select: function(event, ui){
        $scope.keyword = ui.item.value;
        $scope.search();
      },
      source: acData
    });

    return acData;
  };

  /**
   * load more products for the infinite loop
   */
  $scope.loadMore = function(){
    if ($scope.products.length >= $scope.allProducts.length) return;

    var st = $scope.products.length;
    for(var i = 0; i < 5 || !$scope.prodToShow.length; i++) {
      var key = st + i;
      if (key > $scope.allProducts.length - 1) return;
      $scope.products.push($scope.allProducts[key]);
    }

  };

  /**
   * Redirect to the checkout page
   * @param disabled
   */
  $scope.goToCheckout = function(disabled){
    if (disabled || !$rootScope.cart.purchaseEnabled) {
      return;
    }
    $location.path('/checkout/shipping');
  };

  /**
   * Get image thumbnail for product
   * @param imgArray
   * @return {string} image url
   */
  $scope.ProductThumbImg = function(imgArray){
    for(var i in imgArray){
        if(imgArray[i].indexOf('/thumb/') !== -1 ){
            return imgArray[i];
        }
    }
  };

  ///////////////// MAIN ////////////////////////////////
 _init();

}]);

Next Steps

In this section, we discussed the GET Products endpoint and how to use this data to display a catalog of products in our app. In the next section, we’ll discuss the Product Information endpoints.

Next: Display Product Information for a given product

Product Information (General)

Overview

First Data provides several APIs for displaying product-related images. Such endpoints are useful when used on a product-specific page. You can see an example here.

Our API lets you display comprehensive and detailed product information for every product listed in our store. This includes descriptions, features, images, pricing, specifications, items included, recommended products, etc.

Relevant information for each product:

Links below lead to detailed API documentation of the specific endpoints for Product Information:

Over the next few sections, we’ll discuss various product endpoints. All product-related javascript is stored in the js/product.js file and the corresponding HTML view is stored in the view/product.html file. We’ll be referencing code snippets from these files so please make sure you’re acquianted with them.


Next Steps

Learn how to use the Product Information APIs:

Next: Product Details

Skip to: Product Features, Product Specs, Product Includes, FAQs or Recommended Products

Product Details

Overview

What are the Product Details that can be displayed?

• Name
• Price
• Description
• Up to 5 images



API: GET Products/Details

Check out the detailed API documentation of the GET Products/Details API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Now that we’ve introduced the product endpoints in the previous section, we’ll take an in-depth look at displaying Product Details in our app. To do this, we’ll use the GET Products/Details endpoint.

This endpoint is ideal for retrieving basic product information such as name, price, description, etc. As you can see in the below screenshot, the data displayed below is populated using this endpoint.

The GET Products/Details API can be used to display basic product information:

Example user interface displaying Product Details Example user interface displaying Product Details

Frontend example

Displaying basic product information is simple and only requires a GET request to the First Data Marketplace API. When the user selects a particular product on screen, we need to display that item and call the relevant product endpoint(s) to retrieve the corresponding data for each product.

Each product is linked to a productId, which is a unique identifier associated with each particular product. We’ve setup our app so that the productId is passed in the URL parameters and then query the First Data Marketplace API.

The below code is a section of the full Product Information page, created using information returned from the GET Products/Details API.

HTML

This file can be found at
view/product.html.

<div class="column-9">
 <h1>{{bundle_info.productName}} <span class="price">${{bundle_info.price | numberNF : 2}}</span> </h1>
 <h4 ng-show="min_lease_amt"><a class="link"  ng-click="leaseProduct(bundle_info)">Lease</a> for as low as <strong>{{min_lease_amt | currency}}/month</strong></h4>

 <p>{{bundle_info.productLongDescription}}</p>
 <div class="shop-product-actions">
   <a class="link-bold" id="add-to-cart" ng-click="addToCart()">Add to Cart</a>
   <!-- <span>|</span>
   <a ng-if="min_lease_amt" class="link-bold" id="lease-now" ng-click="leaseProduct(bundle_info)">Lease Now</a> -->
 </div>
 <!-- <p><i class="fa fa-credit-card fa-lg"></i> Credit Card Processing @ 2.69% + 5 cents per swipe*<br> <span class="small">*3.69% + $0.05 per non-swiped transactions</span> <a id="pricing-terms-toggle" ng-init="showTc = false" class="small link green" style="cursor:pointer;" ng-click="showTc = !showTc">{{showTc ? 'Hide' : 'View'}} Terms &amp; Conditions</a></p> -->
 <div id="pricing-terms" class="small" ng-show="showTc">
   <br>
   <p>Offer applies to new Clover Station, Mobile or Mini clients only.</p><br>
   <p>Transactions will be billed according to transaction type:</p>
   <ul>
     <li>A rate of 2.69% + $0.05 per transaction fee applies to all credit and debit swiped transactions (sometimes referred to as "card present" transactions). Chip-enabled "dipped" transactions will be billed at the swiped rate.</li>
     <li>A rate of 3.69% + $0.05 per transaction fee applies to all credit and debit non-swiped transactions. Most manually "keyed" transactions will be billed at the non-swiped rate.</li>
   </ul><br>
   <p>Please review your Merchant Processing Agreement for more information about these fees.</p>
   <p>Program requires purchase of Clover point-of-sale hardware, security protection. A software plan may be required. Wireless/data access services are not included.</p><br>
   <p>The Clover trademark and logo are owned by Clover Network, Inc., a First Data company</p>
 </div>
</div>

In our JavaScript code, we call the getProduct() method to make a GET request to the GET Products/Details API and store the response data (JSON) in $scope. Then, using the products Controller (ProductsCtrl), we can display information on screen.

JavaScript

This file can be found at
js/product.js.

Request in Different Languages

See example requests in Shell, Python, JavaScript, Java and PHP here.

// Get Product Details
fdService.getProduct($scope.pid)
  .success(function(data, status, headers, config) {
    $scope.bundle_info = data;
    $scope.images = $scope.bundle_info.imageUrls ? $scope.bundle_info.imageUrls : [];

    $rootScope.title = $scope.bundle_info.productName;
    $rootScope.recommendedProductName = $scope.bundle_info.productName;
    $scope.min_lease_amt = 0;
    if (data.pricingModel && data.pricingModel.length) {
      for (var i = 0; i < data.pricingModel.length; i++) {
        if (CONST.PURCHASE_CODE != data.pricingModel[i].purchaseType && data.pricingModel[i].defaultAmt && (!$scope.min_lease_amt || data.pricingModel[i].defaultAmt < $scope.min_lease_amt)) {
          $scope.min_lease_amt = data.pricingModel[i].defaultAmt;
        }
      }
    }
    $scope.thumbImages = [];
    $scope.largeImages = [];
    for(var i in $scope.images){
      if($scope.images[i].indexOf('/thumb/') !== -1){
        $scope.thumbImages.push($scope.images[i]);
      }
      if($scope.images[i].indexOf('/large/') !== -1){
        $scope.largeImages.push($scope.images[i]);
      }
    }
    $scope.changeImage($scope.thumbImages[0]);

  })
  .error(function(data, status, headers, config) {
    $scope.bundle_info = [];
    $location.path('invalid-item');
    $scope.min_lease_amt = 0;
    console.log('error')
  });

Next Steps

In this section we discussed the GET Products/Details API endpoint and how to retrieve relevant Product Details for each product. In the next section, we’ll discuss how to display Product Features.

Next: Product Features

Skip to: Product Specs, Product Includes, FAQs or Recommended Products

Product Features

Overview

API: GET Products/Features

Check out the detailed API documentation of the GET Products/Features API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

The product page is not complete without proper Product Features. This section displays a list of Product Features to users in a simple list format.

To display this content, we’re going to use the GET Products/Features endpoint to retrieve Product Features from the First Data Marketplace API.

The GET Products/Features API can be used to display a list of brief sentences about the product:

Example user interface displaying Product Features Example user interface displaying Product Features

Frontend example

Displaying Product Features is just as easy as displaying Product Details as explained in the previous section.

The below code is a snippet from the Product Information page, created using the information returned from the GET Products/Features API.

In the below HTML sample, we display Product Features stored in $scope. Then, using angular’s ng-repeat directive, we’ll loop through the Product Features and display on screen.

HTML

This file can be found at
web/view/product.html.

<div class="column-12" ng-show="features.length">
   <h3>Features</h3>
   <ul>
     <li ng-repeat="f in features">{{f}}</li>
   </ul>
</div>

JavaScript

This file can be found at
web/js/app/controllers/product.js.

To retrieve this data, we need to invoke the fdService.getFeatures() function. This method makes a GET a request to the First Data Marketplace API’s /features endpoint. We then retrieve the relevant data and store it in $scope for use in our view above.

// Get Product Features
fdService.getFeatures($scope.pid)
.success(function(data, status, headers, config) {
  $scope.features = data;
})
.error(function(data, status, headers, config) {
  $scope.features = [];
  console.log('error')
});

Next Steps

In this section we discussed the GET Products/Features endpoint and how to retrieve relevant features for each product. In the next section, we’ll discuss how to display Product Specs.

Next: Product Specs

Skip to: Product Includes, FAQs or Recommended Products

Product Specifications

Overview

API: GET Products/Specs

Check out the detailed API documentation of the GET Products/Specs API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Your users may want to know more about products you’re selling and particularly specifications such as weight, size, internet connectivity, etc. To solve this problem, we created the GET Products/Specs endpoint.

Luckily, calling the API, downloading the relevant JSON and displaying it on screen will be quite similar to the process defined in the previous two sections.

The GET Products/Specs API can be used to display the hardware/software specifications of the product:

Partial example of user interface displaying Product Specifications Example user interface displaying Product Specifications

Frontend example

The below code is a section of the full Product Information page, created using the information returned from the GET Products/Specs API.

The below HTML snippet defines the structure of the Product Specifications section. Because we want to organize this content accordingly, we’ve decided to display this content in a <table> tag. Then, we display Product Specs in our view. Using Angular’s ng-repeat directive, we can loop through the Product Specs stored in $scope.

HTML

This file can be found at
web/view/product.html.

<div class="container">
  <h3>Hardware Specifications</h3>
  <table id="product-specifications">
    <tr ng-repeat="(key, sps) in specs">
      <th>{{key}}</th>
      <td>
        <p ng-repeat="s in sps track by $index">{{s}}</p>
      </td>
    </tr>
  </table>
</div>

JavaScript

This file can be found at
web/js/app/controllers/product.js.

To retrieve this data, we need to invoke the fdService.getSpecs() method. This method makes a GET request to the First Data Marketplace API’s /specs endpoint. We then retrieve the relevant data and store it in $scope for use in our view above.

// Get product specifications
fdService.getSpecs($scope.pid)
.success(function(data, status, headers, config) {
  $scope.specs = data;
})
.error(function(data, status, headers, config) {
  $scope.specs = {};
  console.log('error')
});

Next Steps

In this section we discussed the GET Products/Specs endpoint, how to retrieve relevant specifications for each product and display that information on screen. In the next section, we’ll discuss how to use the GET Products/Includes endpoint in our app.

Next: Product Includes

Skip to: FAQs or Recommended Products

Product Includes

Overview

API: GET Products/Includes

Check out the detailed API documentation of the GET Products/Includes API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Oftentimes, a particular product may be “bundled” or “linked” with another or a series of products. To handle this scenario, we created the GET Products/Includes endpoint. This endpoint returns included products for any particular product.

We’re going to use the same structure as before to make a call to this endpoint and return the relevant data on screen.

The GET Products/Includes API can be used to display a list of “child” products that are included in a given product.

Example user interface displaying Included Products Example user interface displaying Included Products

Frontend example

The process of displaying includes is easy and simple.

The below code is a section of the full Product Information page, created by using the information returned when using the GET Products/Includes API.

In the below HTML snippet, we define a sample view to organize the basic structure of this section. Then, using the data returned from our call to the API (detailed in the JavaScript section below), we loop through the Product Includes stored in $scope using Angular’s ng-repeat directive.

HTML

This code can be found at
web/templates/included_products.tpl.

<div ng-if="includes.length">
 <section>
   <div class="container" id="product-contents">
     <h3>Includes</h3>
     <div>
       <a class="product-content column-2" ng-repeat="p in includes" data-toggle="modal" data-target="#include-{{p.productId}}-{{timestamp}}">
         <img ng-src="{{p.imageUrls[0] ? p.imageUrls[0] : placeholderImageUrl}}" />
         <p>{{p.productName}}</p>
       </a>
     </div>
   </div>
 </section>

JavaScript

This code can be found in
web/templates/included_products.tpl.

Using the fdService.getProductsList() method, we pass in the unique productId (PID) and then make a GET request to the First Data Marketplace API’s /includes endpoint. We then store the returned data (JSON) in $scope and using the above HTML view, display it on screen.

// Get Products List
fdService.getProductsList($scope.pid)
  .success(function(data, status, headers, config) {
    $scope.includes = data;
  })
  .error(function(data, status, headers, config) {
    $scope.includes = [];
    console.log('error')
  });

Next Steps

In this section we discussed the GET Products/Includes endpoint, how to retrieve relevant includes for each product and display that information on screen. In the next section, we’ll discuss how to use the Recommended Products endpoint in our app.

Next: Recommended Products

Skip to: FAQs

Overview

API: GET Products/Recommended

Check out the detailed API documentation of the GET Products/Recommended API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Many eCommerce stores offer customers Recommended Products based on what other users have bought in the past. Our sample app also includes this functionality. You can tap into this by calling the GET Products/Recommended endpoint in your app.

In this section, we’ll take a look at how to make a request to the Recommended Products endpoint, save the returned data (JSON) and display it on screen accordingly.

The GET Products/Recommended API can be used to display a list of products that are recommended or frequently bought together with a given product.

Example user interface displaying Recommended Products Example user interface displaying Recommended Products

Frontend example

Displaying Recommended Products in our app is an easy and straightforward process! Similar to the previous sections, we’re going to make a GET request to the First Data Marketplace API’s Recommended Products endpoint.

In the below HTML snippet, we define a sample view to organize the basic structure of this section. Then, using the data returned from our call to the API (detailed in the JavaScript section below), we loop through the Product Includes stored in $scope using Angular’s ng-repeat directive.

The below code is a section of the full Product Information page, created using the data returned from the GET Products/Recommended API.

HTML

This code can be found at
web/templates/recommended.tpl.

<section id="product-accessories" ng-show="recommendedBundles.length">
  <div class="container">
    <h2>Customers have also purchased these products</h2>
    <div class="product-accessory column-2" ng-repeat="b in recommendedBundles | limitTo : 5">
      <a class="link-bold" ng-href="#/product/{{b.productId}}"><img ng-src="{{b.imageUrls[0] ? b.imageUrls[0] : placeholderImageUrl}}"></a>
      <p>{{b.productName | limitToEllipsis:20:0:480}}</p>
      <a class="link-blue" ng-href="#/product/{{b.productId}}">View Details</a>
    </div>
    <div class="product-accessory column-2">
      <a class="link-bold" href="#/products"><img src="img/more-item.jpg"></a>
    </div>
  </div>
</section>

Using the fdService.getRecommendedBundles() method, we pass in a unique productId (PID). This function then makes a GET request to the First Data Marketplace API’s /recommended endpoint and then stores the returned data (JSON) in $scope and using the above HTML view, displays it on screen.

JavaScript

This code can be found at
web/js/app/controllers/product.js.

// Get Recommended bundles for this product
fdService.getRecommendedBundles($scope.pid)
.success(function(data, status, headers, config) {
  $scope.recommendedBundles = data;
})
.error(function(data, status, headers, config) {
  $scope.recommendedBundles = [];
  console.log('error')
});

Next Steps

In this section we discussed the GET Products/Recommended endpoint and how to retrieve Recommended Products. We also discussed how to display that information on screen to our users using Angular’s ng-repeat directive. In the next section, we’ll discuss the FAQ Endpoint!

Next: FAQs

Skip to: Learn about how to get Pricing for Equipment.

Product FAQs

Overview

What information is available for the FAQs?

• Question
• Short Answer
• URL to article



API: GET Products/FAQ

Check out the detailed API documentation of the GET Products/FAQ API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Our final product endpoint allows you to display Frequently Asked Questions, or FAQs, in your app. A common part of an eCommerce store, FAQs help to build trust and ensure your customers get the answers they need before making a purchase. We’ve built an endpoint to display just this information!

The GET Products/FAQ API can be used to display a list of Frequently Asked Questions (FAQs) for a product. The API returns up to 6 FAQ entries but you can choose to display as many or few of them as you like.

Example user interface displaying FAQs Example user interface displaying FAQs

Frontend example

Similar to the previous sections, we’re going to make a GET request to the First Data Marketplace API’s GET Products/FAQ endpoint.

In our demo app, FAQs are displayed in a list for optimum readability.

In the below HTML snippet, we define a sample view to organize the basic structure of this section. Then, using the data returned from our call to the API (detailed in the JavaScript section below), we loop through the Product FAQs stored in $scope using Angular’s ng-repeat directive.

The below code is a section of the full Product Information page, created by using the information returned when using the GET Products/FAQ API.

HTML

This code can be found at
web/templates/faq.tpl.

<section id="faq" ng-show="faqs.length">
    <div class="container">
      <h2>Commonly Asked Questions</h2>
      <div class="faq-question" ng-repeat="f in faqs track by $index">
        <i class="fa fa-info-circle"></i>
        <a ng-href="{{f.url}}" target="_blank">{{f.header}}</a>
        <p>{{f.shortAnswer | limitToEllipsis : 230}}</p>
      </div>
      <div class="faq-question">
        <i class="fa fa-ellipsis-h"></i>
        <a href="https://gyftteam.atlassian.net/wiki/display/KB/Knowledge+Base" target="_blank">More</a>
      </div>
    </div>
  </section>

</div><!-- end .content -->

Using the fdService.getFaqs() method, we pass in a unique productId (PID). This function then makes a GET request to the First Data Marketplace API’s /faq endpoint and then stores the returned data (JSON) in $scope and using the above HTML view, displays it on screen.

JavaScript

This code can be found at
web/js/app/controllers/product.js.

// Get FAQ list for product
fdService.getFaqs($scope.pid)
.success(function(data, status, headers, config) {
  $scope.faqs = data;
})
.error(function(data, status, headers, config) {
  $scope.faqs = [];
  console.log('error')
});

Next Steps

Now you have all the Product Information.

Next: Learn about adding products to your Shopping Cart.

Skip To: Credit Card Processing Pricing for Equipment, Acquiring Pricing or Global Pricing.

Shopping Cart

Overview

API: POST Cart/Validate

Check out the detailed API documentation of the POST Cart/Validate API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

In order to track the user’s activity throughout the site, we’ll need a Shopping Cart. Similar to many other eCommerce sites, the Shopping Cart will allow our customers to add and manage items in their virtual “cart” while they shop on our site. Items can be added, removed and modified (i.e. change quantity, edit purchasing options, etc).

First Data does not provide a Shopping Cart API. Instead, this section will focus on the frontend logic that powers the Shopping Cart. However, we do support a validation API to check the contents of your Cart before checkout.

Example user interface displaying the Shopping Cart with one product added
Example user interface displaying Shopping Cart

Frontend example

How does this work?

Check out the Demo Marketplace to see the Shopping Cart in action.

In the below HTML snippet, we define a sample view to organize the basic structure of the Shopping Cart. The cart’s logic is housed in the CartCtrl controller. In our view, we check to see if the user has any items selected (the cart should not be shown if the user has not added any items) as well as display transaction fee information, an order summary, etc.

The below code is an example of a Shopping Cart interface that can be built into other pages (such as the Product Information page) in your Marketplace.

HTML

This code can be found at
web/templates/cart.tpl.

<div ng-controller="CartCtrl" id="cart" class="column-4" ng-class="{'faded': showTrDetailBox}" ng-show="cart.total_qty || cart.payment_types" ng-init="showTrDetailBox = false; sampleTransAmount = 25;">

  <div class="transaction-fee-detail" ng-show="showTrDetailBox">
    <p class="sub">Transaction fee detail <a class="transaction-fee-detail-toggle" ng-click="showTrDetailBox = false">Hide Details <i class="fa fa-times"></i></a></p>
    <table class="cart-items">
      <tr>
        <td colspan="2" align="center" class="align-center">
          <p><strong>Here is the rate detail</strong></p>
        </td>
      </tr>
      <tr>
        <td>Swiped</td>
        <td class="align-right"> 2.69% + $0.05</td>
      </tr>
      <tr>
        <td>Non-swiped</td>
        <td class="align-right"> 3.69% + $0.05</td>
      </tr>
      <tr>
        <td colspan="2" align="center" class="align-center">
          <p><strong>Sample costs per sale amount</strong></p>
          <table id="sample-amount-toggle">
            <tr>
              <td class="sample-amount-toggle" ng-class="{'selected': 5 == sampleTransAmount}" ng-click="sampleTransAmount = 5"><a>$5</a></td>
              <td class="sample-amount-toggle" ng-class="{'selected': 10 == sampleTransAmount}" ng-click="sampleTransAmount = 10"><a>$10</a></td>
              <td class="sample-amount-toggle" ng-class="{'selected': 25 == sampleTransAmount}" ng-click="sampleTransAmount = 25"><a>$25</a></td>
              <td class="sample-amount-toggle" ng-class="{'selected': 100 == sampleTransAmount}" ng-click="sampleTransAmount = 100"><a>$100</a></td>
            </tr>
          </table>
        </td>
      </tr>
      <tr>
        <td>Swiped</td>
        <td class="align-right"> ${{sampleTransAmount * 0.0269 + 0.05 | number : 2}}  ~ {{(sampleTransAmount * 0.0269 + 0.05) * 100 / sampleTransAmount | number : 2}}%</td>
      </tr>
      <tr>
        <td>Non-swiped</td>
        <td class="align-right"> ${{sampleTransAmount * 0.0369 + 0.05 | number : 2}}  ~ {{(sampleTransAmount * 0.0369 + 0.05) * 100 / sampleTransAmount | number : 2}}%</td>
      </tr>
    </table>
    <p class="sub transaction-fee-detail-toggle" ng-click="showTrDetailBox = false">Hide Details</p>
  </div>
  <div class="cart-contents" id="order-summary-container">

    <h2>Order Summary</h2>
    <p class="sub">One Time Cost</p>
    <table id="cart-items" ng-show="cart.total_purchase_qty || cart.payment_types || (cart.onetimeFees | lengthOfObject) || (!cart.purchaseEnabled && cart.total_lease_qty)">
      <tr ng-repeat="(key, p) in cart.data">
        <td>
          <div ng-if="p.term == CONST.PURCHASE_CODE || p.term == CONST.OWNED_CODE">
           <p><a class="link" ng-href="#/product/{{p.id}}">{{p.name}}</a></p>
           <div id="cart-item-actions">Quantity: <span ng-hide="isAllowEdit()">{{p.qty}}</span>
             <span ng-show="isAllowEdit()">
               <select ng-model="p.qty" ng-change="qtyChanged()" >
                 <option ng-repeat="n in [] | range_s:1:10" ng-value="n">{{n}}</option>
               </select>
               <a class="link" id="remove-from-cart" ng-click="removeFromCart(p.id)">Remove</a>
             </span>
           </div>
           <p><a ng-show="isAllowEdit() && p.min_lease_amount" ng-click="leaseProduct(p)" class="link small lease-now">Lease for for as low as {{p.min_lease_amount|currency}}/mo</p>
         </div>
        </td>
        <td class="align-right"><div ng-if="p.term == CONST.PURCHASE_CODE || p.term == CONST.OWNED_CODE"><div ng-if="p.term == CONST.PURCHASE_CODE || p.term == CONST.OWNED_CODE">${{p.price | numberNF : 2}}</div></div></td>
      </tr>
      <tr ng-if="cart.onetimeFees | lengthOfObject" ng-repeat="fee in cart.onetimeFees | orderByObj:'name'">
         <td>
           <p>{{fee.name}}</p>
         </td>
         <td class="align-right">${{fee.amount | numberNF : 2}}</td>
       </tr>


      <tr class="product-requirement-notification" ng-repeat="err in cart.validation.carterrors" ng-hide="cart.validation.iscartvalid">
        <td colspan="2">
          <p class="red"><strong>Required:</strong> {{err.errormessage}}</p>
          <div id="cart-item-actions">
            <a class="link" id="remove-from-cart" ng-href="#/products/t/{{err.errortype}}">Browse Products</a>
          </div>
        </td>
      </tr>
    </table>
    <table id="order-summary">
      <tr ng-show="cart.total_purchase_qty">
        <td>Total before tax</td>
        <td class="align-right">${{cart.amount + cart.onetimeAmount | numberNF : 2}}</td>
      </tr>
      <tr>
        <td>Shipping & handling</td>
        <td class="align-right">{{cart.shipping_amount ? '$' + cart.shipping_amount : 'Free'}}</td>
      </tr>
      <tr>
        <td><span ng-show="cart.taxPercent < 0 || !cart.shippingAddress.zip || !cart.shippingAddress.city">Estimated tax</span><span ng-hide="cart.taxPercent < 0 || !cart.shippingAddress.zip || !cart.shippingAddress.city">Tax</span></td>
        <td class="align-right">{{cart.tax ? cart.tax : (cart.taxPercent >= 0 ? 0 : 'TBD' ) | numberDollar : 2}}</td>
      </tr>
      <tr id="order-summary-total">
        <td>One-Time Total</td>
        <td class="align-right">${{cart.total + cart.onetimeAmount | number : 2}}</td>
      </tr>
    </table>

    <div ng-show="(cart.product_fees | lengthOfObject) || (cart.mFees | lengthOfObject) || cart.total_lease_qty">
     <p class="sub cart-table-toggle" ng-click="showRecFee = !showRecFee">Recurring Fee <i ng-show="allowExpand" class="fa cart-table-toggle" ng-class="{'fa-chevron-down': !showRecFee, 'fa-chevron-up': showRecFee}"></i><span>${{cart.total_product_fee_amount + cart.mfeeAmount + cart.lease_amount | number : 2}}/mo</span></p>
     <table class="cart-items" id="recurring-fees" ng-show="showRecFee || !allowExpand">
       <tr ng-if="cart.product_fees | lengthOfObject" ng-repeat="fee in cart.product_fees">
         <td>
           <p>{{fee.name}}</p>
         </td>
         <td class="align-right">${{fee.amount | numberNF : 2}}/mo</td>
       </tr>
        <tr class="lease" ng-repeat="(key, p) in cart.data" ng-show="cart.total_lease_qty">
         <td>
          <div ng-if="p.term != CONST.PURCHASE_CODE && p.term != CONST.OWNED_CODE">
            <p><a class="link" ng-href="#/product/{{p.id}}">{{p.name}}</a></p>
            <div id="cart-item-actions">
              <div>
                Quantity: <span ng-hide="isAllowEdit()">{{p.qty}}</span>
                <span ng-show="isAllowEdit()">
                   <select ng-model="p.qty" ng-change="qtyChanged()" >
                     <option ng-repeat="n in [] | range_s:1:10" ng-value="n">{{n}}</option>
                   </select>
                 </span>
              </div>
              <div>
                Leasing Option: Monthly
              </div>
              <div>
                Leasing Term: <span ng-hide="isAllowEdit()">{{p.pmodel.purchaseTypeLabel}}</span>
                <span ng-if="isAllowEdit()">
                 <select id="leasing-term" ng-model="p.term" ng-change="qtyChanged()">
                   <option ng-repeat="m in p.pricingModel | filter:{purchaseType: '!P'}:true | filter:{purchaseType: '!O'}:true" value="{{m.purchaseType}}" >{{m.purchaseTypeLabel}}</option>
                 </select>
                </span>
              </div>
              <span ng-show="isAllowEdit()"><a class="link" id="remove-lease" ng-click="removeFromCart(p.id)">Remove</a></span>
            </div>
          </div>
         </td>
         <td class="align-right" id="leasing-fee"><div ng-if="p.term != CONST.PURCHASE_CODE && p.term != CONST.OWNED_CODE"><div ng-if="p.term != CONST.PURCHASE_CODE && p.term != CONST.OWNED_CODE">{{p.pmodel.defaultAmt|currency}}/mo</div></div></td>
       </tr>
       <tr ng-if="cart.mFees | lengthOfObject" ng-repeat="fee in cart.mFees">
         <td>
           <p>{{fee.name}}</p>
         </td>
         <td class="align-right">${{fee.amount | numberNF : 2}}/mo</td>
       </tr>
       <tr class="order-summary-total">
         <td>Total</td>
         <td class="align-right">${{cart.total_product_fee_amount + cart.mfeeAmount + cart.lease_amount | numberNF : 2}}/mo</td>
       </tr>
     </table>
     <br>
    </div>

    <div ng-if="cart.payment_types">
     <p class="sub cart-table-toggle" ng-click="transactionFee = !transactionFee">Transaction Fee <i ng-show="allowExpand" class="fa cart-table-toggle" ng-class="{'fa-chevron-down': !transactionFee, 'fa-chevron-up': transactionFee}"></i><span ng-show="cart.transaction_fee">{{cart.transaction_fee.rate}}% + {{cart.transaction_fee.fee|currency}}</span><span ng-hide="cart.transaction_fee.rate || cart.transaction_fee.fee">TBD</span></p>
     <table class="cart-items" ng-show="transactionFee || !allowExpand">
       <tr>
         <td>
           <p><strong><a class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
           <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
         </td>
         <td class="align-right"><span ng-show="cart.transaction_fee">{{cart.transaction_fee.rate}}% + {{cart.transaction_fee.fee|currency}}</span><span ng-hide="cart.transaction_fee.rate || cart.transaction_fee.fee">TBD</span></td>
       </tr>
     </table>
    </div>

     <div id="cart-actions">
      <a ng-if="!orderId" ng-hide="page == 'thankyou' || !logged_in" class="link-blue align-center" ng-href="{{!showTrDetailBox ? '#/products/c' : null}}">Continue Shopping</a>
      <a ng-if="page == 'proposal'" ng-href="#/signup" class="btn" ng-class="{'disabled': !orderId}">Sign Up</a>
      <a ng-if="page == 'solution' || page == 'product' || page == 'family' || page == 'processing'" ng-click="!cart.validation.iscartvalid || proceedToCheckout()" class="btn" ng-class="{'disabled': !cart.validation.iscartvalid}">PROCEED TO CHECKOUT</a>
      <a ng-if="page == 'shipping'" class="btn" ng-click="!shippingForm.$valid || !cart.validation.iscartvalid || gotoSummary()" ng-class="{'disabled': !shippingForm.$valid || !cart.validation.iscartvalid}">Review Order</a>

      <a ng-if="page == 'transaction_info'" class="btn" ng-click="!cart.validation.iscartvalid || !transactionInfoForm.$valid || saveTransactionInfo(transactionInfoForm)" ng-class="{'disabled': !cart.validation.iscartvalid || !transactionInfoForm.$valid}">Next</a>

      <div ng-if="page == 'summary'">
        <a class="btn" ng-class="{'disabled': !cart.validation.iscartvalid}" ng-click="!cart.validation.iscartvalid || placeOrder()">Place Order</a>
      </div>
      <br ng-hide="page == 'thankyou'">
      <p class="small">Payment Processing Fees will be determined based on industry, transactional volume, estimated average ticket, and estimated highest ticket size.</p>
    </div>
  </div>
</div>

Using the CartCtrl controller, we define the logic that powers our Shopping Cart. This controller manages all items added, deleted or edited in the cart as well as displays or hides the cart accordingly.

Our removeFromCart() and qtyChanged() methods watch for changes the user may make when interacting with items in the cart. These two methods again internally, make call to validateCart() to check, if the users can proceed to checkout and if not, alert them with cart errors. The cart errors are mostly related to the dependent products that are required to be added in the shopping cart to proceed further.

Finally, the fdService.validateCart() function makes a call to the POST Cart/Validate endpoint for added validation before checkout.

JavaScript

This file can be found at
web/js/app/controllers/cart.js.


/**
 * Cart Controller
 */
app.controller('CartCtrl', ['$scope', '$rootScope', '$window', 'fdService', '$routeParams', 'CONST', '$location', '$timeout', 'filterFilter',
  function($scope, $rootScope, $window, fdService, $routeParams, CONST, $location, $timeout, filterFilter) {

    /**
     * Init function
     * @private
     * @method _init
     */
    var _init = function() {

      $scope.clickedCheckout = false;
      $scope.showRecFee = true;
      $scope.transactionFee = true;
      $scope.disableReviewOrder = false;
      $scope.allowExpand = true;

      $scope.acquiringPricing = [];
      $scope.equipmentPricing = [];
      $scope.globalPricing = [];

      $scope.page = $routeParams.page;


      $scope.orderId = fdService.getOrderId();

      $rootScope.cart = fdService.getCart();

      $scope.$watch(function() {
        return $window.sessionStorage;
      }, function(newVal, oldVal) {
        $scope.orderId = fdService.getOrderId();
      }, true);

      $scope.$watch(function() {
        return $rootScope.cart;
      }, function(newVal, oldVal) {
        $scope.cart = newVal;
      }, true);

      if (($scope.orderId &&
                ('shipping' == $scope.page
                    || 'multi-locations' == $scope.page
                    || 'transaction_info' == $scope.page
                  ))
                  || 'thankyou' == $scope.page
                  || 'summary' == $scope.page
                  || 'proposal' == $scope.page) {
        $scope.allowExpand = false;
        $scope.cart = $rootScope.cart = fdService.getOrderedCart($scope.orderId);
      }

      $("#view-fees-modal").on('show.bs.modal', function() {
        $scope.acquiringPricing = fdService.getAcquiringPricingStorage();
        $scope.acquiringDataGrouping($scope.acquiringPricing);
        console.log($scope.acquiringPricing)
        $scope.equipmentPricing = fdService.getEquipmentPricingStorage();
        $scope.globalPricing = fdService.getGlobalPricingStorage();
        if (!$scope.$$phase) {
          $scope.$apply();
        }
      });
    };

    /**
     * Acquiring Data Grouping
     * @method acquiringDataGrouping
     * @param data acquiringData
     */
    $scope.acquiringDataGrouping = function(data) {
        var result = {};
        var discountRates = [];
        var groupedDiscountRates = {};
        if(undefined != data && undefined != data.discountRates){
            for (var i = 0; i < data.discountRates.length; i++) {
                var temp = data.discountRates[i];
                if (groupedDiscountRates[data.discountRates[i].groupName] && data.discountRates[i].groupName != '') {
                    groupedDiscountRates[data.discountRates[i].groupName].push(temp);
                } else {
                    if (data.discountRates[i].groupName != '')
                        groupedDiscountRates[data.discountRates[i].groupName] = [temp];
                    else {
                        discountRates.push(temp);
                    }
                }
            }
        }
        //setup cardPresentDiscountRates
        if(undefined != data && undefined != data.cardPresentDiscountRates){
            for (var i = 0; i < data.cardPresentDiscountRates.length; i++) {
                var temp = data.cardPresentDiscountRates[i];
                if (result[data.cardPresentDiscountRates[i].groupName] && data.cardPresentDiscountRates[i].groupName != '') {
                    result[data.cardPresentDiscountRates[i].groupName][0].cardPresentDiscountRates.push(temp);
                } else {
                    var tempData = [];
                    tempData.push(temp);

                    tempData[0].cardPresentDiscountRates = [];
                    tempData[0].cardNotPresentDiscountRates = [];

                    if (data.cardPresentDiscountRates[i].groupName != ''){
                        tempData[0].cardPresentDiscountRates.push(angular.copy(temp));
                        result[data.cardPresentDiscountRates[i].groupName]=tempData;
                    }
                }
            }
        }
        //setup cardNotPresentDiscountRates
        if(undefined != data && undefined != data.cardNotPresentDiscountRates){
            for (var i = 0; i < data.cardNotPresentDiscountRates.length; i++) {
                var temp = data.cardNotPresentDiscountRates[i];
                if (result[data.cardNotPresentDiscountRates[i].groupName] && data.cardNotPresentDiscountRates[i].groupName != '') {
                    result[data.cardNotPresentDiscountRates[i].groupName][0].cardNotPresentDiscountRates.push(temp);
                } else {
                    var tempData = [];
                    tempData.push(temp);

                    tempData[0].cardPresentDiscountRates = [];
                    tempData[0].cardNotPresentDiscountRates = [];

                    if (data.cardNotPresentDiscountRates[i].groupName != ''){
                        tempData[0].cardNotPresentDiscountRates.push(angular.copy(temp));
                        result[data.cardNotPresentDiscountRates[i].groupName]=tempData;
                    }
                }
            }
        }
        //setup scope arrays and objects
        $scope.groupedPricingDetails = result;
        $scope.discountRates = discountRates;
        $scope.groupedDiscountRates = groupedDiscountRates;
    }

    /**
     * Grouping button click
     * @method grouping
     * @param {number} index
     */
    $scope.grouping = function(index) {
        angular.element('.toggle-rates-children' + index).children('i').toggleClass('fa-angle-double-down fa-angle-double-up');
        angular.element('.toggle-rates-children' + index).parent('div').children('table.rate-child' + index).slideToggle('fast');
    }

    /**
     * Subgrouping button click
     * @method grouping
     * @param {number} index
     */
    $scope.subgrouping = function(index) {
        angular.element('.toggle-rates-sub-children' + index).children('i').toggleClass('fa-angle-double-down fa-angle-double-up');
        angular.element('.toggle-rates-sub-children' + index).parent('td').parent('tr').parent('tbody').parent('table').children('tbody.rate-sub-child').slideToggle('fast');
    }

    /**
     * remove product from cart
     * @method removeFromCart
     * @param pid product Id
     */
    $scope.removeFromCart = function(index) {
      $rootScope.cart.data.splice(index, 1);
      // delete $rootScope.cart.data[pid];
      fdService.validateCart($rootScope.cart)
        .success(function(data, status, headers, config) {
          $rootScope.cart.validation = data;
          $scope.cart = $rootScope.cart;
          $scope.cartChanged();
          if (data.iscartvalid)
            fdService.updatePricing();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });

      $scope.cart = $rootScope.cart;
      $scope.cartChanged();

      if (0 === $scope.cart.total_qty) {
        $location.path('/');
      }
    };

    /**
     * Calling in case of changing quantity.
     * @method qtyChanged
     */
    $scope.qtyChanged = function() {
      fdService.resetCartOverridePricing($scope.cart);
      fdService.updatePricing(function() {
        $rootScope.cart = $scope.cart = fdService.getCart();
      });
      $scope.cartChanged();
    };

    /**
     * Calling in case of changing cart.
     * @method cartChanged
     */
    $scope.cartChanged = function() {
      fdService.clearOrderId();
      $rootScope.cart = $scope.cart = fdService.cartChanged($scope.cart);
      $scope.orderId = fdService.getOrderId();
    };

    /**
     * Remove lease from cart
     * @method removeLease
     * @param p product object
     */
    $scope.removeLease = function(p) {
      $scope.cart.data[p.id].term = CONST.PURCHASE_CODE;
      fdService.validateCart($scope.cart)
        .success(function(data, status, headers, config) {
          $scope.cart.validation = data;
          $scope.cartChanged();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });

      fdService.updatePricing();
      $scope.cartChanged();
    };

    /**
     * Remove processing product from cart
     * @method removeProcessing
     * @param p processing product object
     */
    $scope.removeProcessing = function(p) {
      delete $scope.cart.payment_types.products[p.id];
      if (!Object.keys($scope.cart.payment_types.products).length) {
        $scope.cart.payment_types = null;
      }
      fdService.validateCart($scope.cart)
        .success(function(data, status, headers, config) {
          $scope.cart.validation = data;
          $scope.cartChanged();
          if (data.iscartvalid)
            fdService.updatePricing();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });

      $scope.cartChanged();
    };

    /**
     * remove transaction product
     * @method removeTransactionProduct
     * @param p
     */
    $scope.removeTransactionProduct = function(p) {

      var index =  $rootScope.cart.transaction_products.map(function(e) { return e.id; }).indexOf(p.id);

      if (-1 === index) {
        return;
      }

      $rootScope.cart.transaction_products.splice(index, 1);

      fdService.validateCart($scope.cart)
        .success(function(data, status, headers, config) {
          $scope.cart.validation = data;
          $scope.cartChanged();
          if (data.iscartvalid)
            fdService.updatePricing();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });

      $scope.cartChanged();
    };

    /**
     * Remove payment types from cart
     * @method removePaymentTypes
     */
    $scope.removePaymentTypes = function() {
      $scope.cart.payment_types = null;
      fdService.validateCart($scope.cart)
        .success(function(data, status, headers, config) {
          $scope.cart.validation = data;
          $scope.cartChanged();
          if (data.iscartvalid)
            fdService.updatePricing();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });

      $scope.cartChanged();
    };

    /**
     * Lease product
     * @method leaseProduct
     * @param {Object} p product
     */
    $scope.leaseProduct = function(p) {

      var index = fdService.getCartProductIndex($rootScope.cart, p);
      $scope.cart.data.splice(index, 1);

      $rootScope.cart = $scope.cart = fdService.leaseProduct(p, $scope.cart, p.category);
      $scope.showRecFee = true;
      fdService.validateCart($scope.cart)
        .success(function(data, status, headers, config) {
          $scope.cart.validation = data;
          $scope.cartChanged();
          if (data.iscartvalid)
            fdService.updatePricing();
        })
        .error(function(data, status, headers, config) {
          console.log('error');
        });
    };

    /**
     * Save transaction info in session
     * @method saveTransactionInfo
     */
    $scope.saveTransactionInfo = function() {

      $scope.transactionFormData.category = $scope.category.name;
      fdService.storeTransactionInfo($scope.transactionFormData);

      fdService.initPricingData(function(status) {
        if (status) {
          $rootScope.cart = $scope.cart = fdService.getCart();
          $location.path('/checkout/shipping');
        } else {
          $location.path('400');
        }
      }, null, fdService.getEquipmentPricingStorage(), fdService.getGlobalPricingStorage());
    };

    /**
     * Submit proposal
     * @method sendProp
     */
    $scope.sendProp = function() {
      fdService.submitProposal();
    };

    /**
     * Get transaction info
     * @method getTI
     * @return {Object} with transaction info
     */
    $scope.getTI = function() {
      return fdService.getTransactionInfo();
    };

    /**
     * Call review order service
     * @method reviewOrder
     */
    $scope.reviewOrder = function() {
      if ($scope.disableReviewOrder)
        return;
      $scope.disableReviewOrder = true;
      var orderId = fdService.getOrderId();
      $rootScope.$emit('Update_address_cart');
      fdService.reviewOrder(orderId)
        .success(function(data, status, headers, config) {
          $scope.disableReviewOrder = false;
          var cart = orderId ? fdService.getOrderedCart(orderId) : fdService.getCart();
          fdService.storeOrderId(data.orderId);
          fdService.storeOrderedCart(data.orderId, cart);
          fdService.clearTmpOrderId();
          $scope.gotoUrl('/checkout/summary');
        })
        .error(function(data, status, headers, config) {
          $scope.disableReviewOrder = false;
          console.log('error');
        });
    };

    /**
     * Redirect to url
     * @method gotoUrl
     * @param url where to redirect
     */
    $scope.gotoUrl = function(url) {
      $location.path(url);
    };

    /**
     * return pricing forms OK status
     * @method pricingFormsOk
     * @return {boolean}
     */
    $scope.pricingFormsOk = function() {
      if (typeof $rootScope._pricingFormsOk == 'function') {
        return $rootScope._pricingFormsOk();
      }
      return true;
    };

    /**
     * Redirect to the checkout page or transation info
     * @method proceedToCheckout
     */
    $scope.proceedToCheckout = function() {
      var ep = fdService.getEquipmentPricingStorage();
      var url;
      if ($rootScope.cart.num_locations > 1 && !$rootScope.cart.num_locations_selected) {
        url = '/multi-locations';
      } else if ($scope.getTI() && ep) {
        url = '/checkout/shipping';
      } else {
        url = '/transaction/info';
      }
      $timeout(function() {
        $scope.gotoUrl(url);
      });
    };

    /**
     * Redirect to checkout page from multi locations
     * @method proceedToCheckoutML
     */
    $scope.proceedToCheckoutML = function() {

      var ep = fdService.getEquipmentPricingStorage();
      if ($scope.getTI() && ep) {
        var url = '/checkout/shipping';
      } else {
        var url = '/transaction/info';
      }
      $timeout(function() {
        $scope.gotoUrl(url);
      });
    };

    /**
     * Check if cart edit is allowed
     * @method isAllowEdit
     * @return {boolean}
     */
    $scope.isAllowEdit = function() {
      if ('shipping' == $scope.page) {
        return false;
      }
      if ('thankyou' == $scope.page) {
        return false;
      }
      if ('summary' == $scope.page) {
        return false;
      }
      if ('proposal' == $scope.page) {
        return false;
      }
      if ('transaction_info' == $scope.page) {
        return false;
      }
      if ('cart' == $scope.page) {
        return false;
      }

      return true;
    };

    /**
     * Check if products clickable
     * @method isProductsClickable
     * @return {boolean}
     */
    $scope.isProductsClickable = function() {
      if ('thankyou' == $scope.page) {
        return false;
      }
      if ('summary' == $scope.page) {
        return false;
      }
      if ('proposal' == $scope.page) {
        return false;
      }
      if ('cart' == $scope.page) {
        return false;
      }
      return true;
    };

    /**
     * Load unique lease options
     * @method models
     * @param {} pricingModel
     * @return {} filteredOptions
     */
    $scope.models = function(pricingModel) {
      var filteredOptions = [];
      angular.forEach(pricingModel, function(item) {
        var index = filteredOptions.map(function(p) {
          return p.paymentType;
        }).indexOf(item.paymentType);
        if (index === -1) {
          filteredOptions.push(item);
        } else {
          filteredOptions[index] = item;
        }
      });
      return filteredOptions;
    };

    /**
     * Payment Type Changed
     * @method paymentTypeChanged
     * @param product
     */
    $scope.paymentTypeChanged = function(product) {
      var leaseTypes = [];
      var index = 0;
      if (product.termPaymentType == 'Lease') {
        leaseTypes = filterFilter(product.pricingModel, {purchaseType: 'LT'});
        //check for LT36 type lease if available.
        var leaseIndex = leaseTypes.map(function(p) {return p.purchaseType;}).indexOf('LT36');
        index = leaseIndex == -1 ? 0 : leaseIndex;
      } else if (product.termPaymentType == 'Installment') {
        leaseTypes = filterFilter(product.pricingModel, {purchaseType: 'IP'});
      } else if (product.termPaymentType == 'Rent') {
        leaseTypes = filterFilter(product.pricingModel, {purchaseType: 'R'});
      }
      if (leaseTypes.length > 0) {
        product.term = leaseTypes[index].purchaseType;
      }
      $scope.qtyChanged();
    };

    /**
     * Change Category
     * @method changeCategory
     * @param categoryName
     */
    $scope.changeCategory = function(categoryName) {
      if (!$scope.categories) {
        fdService.getCategories().success(function(data, status, headers, config) {
            $scope.categories = data;
            $scope.updateCategoryInSession(categoryName);
          })
          .error(function(data, status, headers, config) {
            $location.path('/400');
          });
      } else {
        $scope.updateCategoryInSession(categoryName);
      }
    }

    /**
     * Update Category in Session
     * @method updateCategoryInSession
     * @param categoryName
     */
    $scope.updateCategoryInSession = function(categoryName) {
         var index = $scope.categories.map(function(cat) { return cat.name; }).indexOf(categoryName);
      if (index != -1) {
        var category = $scope.categories[index];
        fdService.storeCategoryInSession(category);
        $rootScope.$emit('Category_Change');
      }
    }

    ///////////////// MAIN ////////////////////////////////

    _init();

  }
]);


Next Steps

In this section we discussed how to create and manage a Shopping Cart using Angular and used the POST Cart/Validate API for product validate before checkout. In the next section, we’ll discuss the Pricing Endpoints!

Next: Pricing Information (General)

Pricing Information (General)

Overview

Now that we’ve discussed all the product endpoints, it’s time to turn our attention to the pricing endpoints. The pricing endpoints are a group of POST APIs that allow developers to send product data to the First Data Marketplace API and returns Pricing Information for selected items.

Relevant information for each pricing endpoint:

Links below lead to detailed API documentation of the specific endpoints for Pricing Information:

Over the next few pages, we’ll discus various pricing endpoints. Please refer to the source on GitHub.


Next Steps

Learn how to use the Product Information APIs:

Next: Pricing Equipment

Skip to: Pricing Acquiring, Pricing Global

Pricing/Equipment

Overview

API: POST Pricing/Equipment

Check out the detailed API documentation of the POST Pricing/Equipment API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Next, we’ll need to display pricing data for particular products. To do this, we’ve developed the POST Pricing/Equipment API for just this purpose. Using the data return from this endpoint, we’ll then display the information on screen to the user in a popup.

The POST Pricing/Equipment API can be used to get the list of product prices related to a certain product.


Example user interface displaying Equipment Pricing Example user interface displaying Acquiring Pricing

Frontend Example

There are two components to displaying the pricing data on screen. First, we need to display a transaction fee section with a button that indicates the user should click it. Second, we’ll need a popup that can display the relevant pricing information to the user in a clear dialog.

Let’s tackle the transaction fee section first.

In the below HTML snippet, we define a sample view to organize the basic structure of this transaction fee section (we briefly discussed this code in the previous Shopping Cart section).

HTML

This code can be found at
web/templates/cart.tpl.

Transaction Fee Section

<div ng-if="cart.payment_types || cart.transaction_products.length">
    <p class="sub cart-table-toggle" ng-click="transactionFee = !transactionFee">Transaction Fee <i ng-show="allowExpand" class="fa cart-table-toggle" ng-class="{'fa-chevron-down': !transactionFee, 'fa-chevron-up': transactionFee}"></i></p>
    <table class="cart-items" ng-show="transactionFee || !allowExpand">
        <tbody ng-if="cart.payment_types && !(cart.payment_types.groups && cart.payment_types.groups.length)">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">TBD</td>
            </tr>
        </tbody>
        <tbody>
        <tbody ng-repeat="g in cart.payment_types.groups track by $index" ng-if="cart.payment_types && cart.payment_types.groups && cart.payment_types.groups.length">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a> <span class="small">({{g.name}})</span></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">{{g.rate}}% + {{g.fee|currency}}</td>
            </tr>
        </tbody>
        <tbody>
            <tr ng-repeat="p in cart.transaction_products track by $index">
                <td>
                <p><p ng-show="!isProductsClickable()">{{p.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/{{p.parentProduct.id ? 'family' : 'product'}}/{{p.parentProduct.id ? p.parentProduct.id : p.id}}">{{p.name}}</a><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removeTransactionProduct(p)">Remove</a></span></p>
                </td>


                <td class="align-right">
                <span ng-show="p.parentProduct.fee || p.parentProduct.rate">{{p.parentProduct.rate}}% + {{p.parentProduct.fee|currency}}</span><span ng-hide="p.parentProduct">TBD</span>
                </td>
            </tr>
        </tbody>
        <tbody ng-show="cart.payment_types.products">
            <tr>
                <td></td>
                <td class="align-right">
                    <div ng-show="cart.payment_types.products">
                        <p><a class="small link" data-toggle="modal" data-target="#view-fees-modal">View Details</a>
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
</div>

Pricing Popup

Next, we want to display the correct pricing data to our users. We display this data in a popup in our Demo Marketplace. The below HTML snippet defines the pricing popup we’ll be using in this section.

<div ng-controller="CartCtrl" class="modal fade include-detail-modal" tabindex="-1" role="dialog" id="view-fees-modal">
  <div class="vertical-alignment-helper">
    <div class="modal-dialog vertical-align-center">
      <div class="modal-content">
        <div class="modal-header">
          <a class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true"><i class="fa fa-times"></i></span></a>
          <h4 class="modal-title">Rates and Fees</strong></h4>
        </div>
        <div class="modal-body row">
          <div class="rates-details-modal">
            <div class="column-6">
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">{{cart.payment_types.name}}</h3>
                      <strong ng-show="cart.transaction_fee">{{cart.payment_types.groups[0].rate}}% + {{cart.payment_types.groups[0].fee|currency}} is the qualified rate</strong>
                    </th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <!--Card Present & Card Not Present placeholder-->
                  <tr ng-repeat="group in groupedPricingDetails | orderByParentOrder:'parentOrder' track by $index">
                    <td ng-if="group[0].cardPresentDiscountRates.length>=1 || group[0].cardNotPresentDiscountRates.length>=1" colspan=3>
                      <div>
                        <a class="link toggle-rates-children" ng-class="'toggle-rates-children'+$index" ng-click="grouping($index)">
                          <i class="fa fa-lg fa-angle-double-down"></i>
                        </a>
                        <strong>{{group[0].groupName}}</strong>
                        <!--card present-->
                        <table ng-if="group[0].cardPresentDiscountRates.length>=1" class="table rates rate-child rate-child{{$index}}" style="display:none; margin: 10px 0 0 0;">
                          <tbody>
                            <tr>
                              <td>
                                <a class="link toggle-rates-sub-children" ng-class="'toggle-rates-sub-children'+$index" ng-click="subgrouping($index)">
                                  <i class="fa fa-lg fa-angle-double-down"></i>
                                </a>
                                <strong> Card Present </strong>
                              </td>
                              <td class="align-right">{{group[0].rateDefault}}</td>
                              <td class="align-right">{{group[0].defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index" ng-repeat="product in group[0].cardPresentDiscountRates track by $index" style="display:none;">
                            <tr>
                              <td>{{product.productName}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                              <td class="align-right">{{product.defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                        <!--card present end-->
                        <!--card not present-->
                        <table ng-if="group[0].cardNotPresentDiscountRates.length>=1" class="table rates rate-child rate-child{{$index}}" style="display:none; margin: 10px 0 0 0;">
                          <tbody>
                            <tr>
                              <td>
                                <a class="link toggle-rates-sub-children" ng-class="'toggle-rates-sub-children'+$index + 'np'" ng-click="subgrouping($index + 'np')">
                                  <i class="fa fa-lg fa-angle-double-down"></i>
                                </a>
                                <strong> Card Not Present</strong>
                              </td>
                              <td>{{group[0].cardNotPresentDiscountRates[0].rateDefault}}</td>
                              <td>{{group[0].cardNotPresentDiscountRates[0].defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index + 'np'" ng-repeat="product in group[0].cardNotPresentDiscountRates track by $index" style="display:none;">
                            <tr>
                              <td>{{product.productName}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                        <!--card not present end-->
                      </div>
                    </td>
                  </tr>
                  <!--Card Present & Card Not Present placeholder-->
                  <!--grouped discount rates products-->
                  <tr ng-repeat="items in groupedDiscountRates | orderByParentOrder:'parentOrder' track by $index">
                    <td colspan="3">
                      <div>
                        <a ng-if="items.length>=1" class="link toggle-rates-children+'gdr'" ng-class="'toggle-rates-children' + $index+'gdr'" ng-click="grouping($index+'gdr')">
                          <i class="fa fa-lg fa-angle-double-down"></i></a>
                        <strong>{{items[0].groupName}}</strong>
                        <table class="table rates rate-child rate-child{{$index+'gdr'}}" style="margin: 10px 0 0 0;display:none;">
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index" ng-repeat="item in items track by $index">
                            <tr>
                              <td>{{item.productName}}</td>
                              <td class="align-right">{{item.rateDefault}}</td>
                              <td class="align-right">{{item.defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                      </div>
                    </td>
                  </tr>
                  <!--end grouped discount rates products-->
                  <tr ng-repeat="item in discountRates track by $index">
                    <td><strong>{{item.productName}}</strong></td>
                    <td class="align-right">{{item.rateDefault}}</td>
                    <td class="align-right">{{item.defaultAmt}}</td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="column-6">
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">Product Pricing</h3>
                    </th>
                  </tr>
                </thead>
                <tbody style="border: none;">
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <tr ng-repeat="p in equipmentPricing track by $index">
                    <td>{{p.productName}}</td>
                    <td class="align-right"><span>{{p.rateDefault}}</span></td>
                    <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                  </tr>
                </tbody>
              </table>
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">Rates - Applies to all</h3>
                    </th>
                  </tr>
                </thead>
                <tbody style="border: none;">
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <tr ng-repeat="p in globalPricing track by $index">
                    <td>{{p.productName}}</td>
                    <td class="align-right"><span>{{p.rateDefault}}</span></td>
                    <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

The popup can be invoked, or shown on screen, using an on listener on the $("#view-fees-modal") id. This function makes calls to the fdService.getAcquiringPricingStorage(), fdService.getEquipmentPricingStorage() and fdService.getGlobalPricingStorage() methods depending on which type of pricing is selected and then shows the data on screen using the $scope.apply() function.

For this section, only the getEquipmentPricingStorage() is invoked.

JavaScript

JavaScript

This code can be found at
js/app/controllers/cart.js.

$("#view-fees-modal").on('show.bs.modal', function () {
  $scope.acquiringPricing = fdService.getAcquiringPricingStorage();
  console.log($scope.acquiringPricing)
  $scope.equipmentPricing = fdService.getEquipmentPricingStorage();
  $scope.globalPricing = fdService.getGlobalPricingStorage();
  if (!$scope.$$phase) {
    $scope.$apply();
  }
});

Next Steps

In this section we discussed the POST Pricing/Equipment endpoint and how to retrieve pricing details. In the next section, we’ll discuss the POST Pricing/Acquiring endpoint.

Next: Credit Card Processing Acquiring Pricing

Skip To: Get Global Pricing Products.

Pricing/Acquiring

Overview

How is “Acquiring” pricing different from “Equipment” pricing?

Acquiring pricing refers to the cost of credit card processing, while Equipment pricing refers to the costs that the merchant incurs for their point-of-sale system.

API: POST Pricing/Acquiring

Check out the detailed API documentation of the POST Pricing/Acquiring API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Now, we’ll need to display acquiring data for particular products. Acquiring data represents credit card transaction fees. To do this, we’ve developed the POST Pricing/Acquiring API for just this purpose. Using the data return from this endpoint, we’ll then display the information on screen to the user in a popup.

The POST Pricing/Acquiring API can be used to get the list of pricing products representing the credit card processing transaction fees and rates.

Example user interface displaying Acquiring Pricing Example user interface displaying Acquiring Pricing

Frontend Example

There are two components to displaying the pricing data on screen. First, we need to display a transaction fee section with a button that indicates the user should click it. Second, we’ll need a popup that displays the relevant pricing information to the user in a clear dialog.

Let’s tackle the transaction fee section first.

In the below HTML snippet, we define a sample view to organize the basic structure of this transaction fee section (we briefly discussed this code in the previous cart section).

Transaction Fee Section

HTML

This code can be found at
web/templates/cart.tpl.


<div ng-if="cart.payment_types || cart.transaction_products.length">
    <p class="sub cart-table-toggle" ng-click="transactionFee = !transactionFee">Transaction Fee <i ng-show="allowExpand" class="fa cart-table-toggle" ng-class="{'fa-chevron-down': !transactionFee, 'fa-chevron-up': transactionFee}"></i></p>
    <table class="cart-items" ng-show="transactionFee || !allowExpand">
        <tbody ng-if="cart.payment_types && !(cart.payment_types.groups && cart.payment_types.groups.length)">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">TBD</td>
            </tr>
        </tbody>
        <tbody>
        <tbody ng-repeat="g in cart.payment_types.groups track by $index" ng-if="cart.payment_types && cart.payment_types.groups && cart.payment_types.groups.length">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a> <span class="small">({{g.name}})</span></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">{{g.rate}}% + {{g.fee|currency}}</td>
            </tr>
        </tbody>
        <tbody>
            <tr ng-repeat="p in cart.transaction_products track by $index">
                <td>
                <p><p ng-show="!isProductsClickable()">{{p.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/{{p.parentProduct.id ? 'family' : 'product'}}/{{p.parentProduct.id ? p.parentProduct.id : p.id}}">{{p.name}}</a><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removeTransactionProduct(p)">Remove</a></span></p>
                </td>


                <td class="align-right">
                <span ng-show="p.parentProduct.fee || p.parentProduct.rate">{{p.parentProduct.rate}}% + {{p.parentProduct.fee|currency}}</span><span ng-hide="p.parentProduct">TBD</span>
                </td>
            </tr>
        </tbody>
        <tbody ng-show="cart.payment_types.products">
            <tr>
                <td></td>
                <td class="align-right">
                    <div ng-show="cart.payment_types.products">
                        <p><a class="small link" data-toggle="modal" data-target="#view-fees-modal">View Details</a>
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
</div>

Pricing Popup

Next, we want to display the correct pricing data to our users. We display this data in a popup in our Demo Marketplace. The below HTML snippet defines the pricing popup we’ll be using in this section.

<div class="modal fade include-detail-modal" tabindex="-1" role="dialog" id="view-fees-modal">
    <div class="vertical-alignment-helper">
        <div class="modal-dialog vertical-align-center">
            <div class="modal-content">
                <div class="modal-header">
                    <a class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true"><i class="fa fa-times"></i></span></a>
                    <h4 class="modal-title">Rates and Fees</strong></h4>
                </div>
                <div class="modal-body row">
                    <div class="rates-details-modal">
                        <div class="column-6">

                            <table class="table rates">
                                <thead>
                                <tr>
                                    <th colspan="3">
                                        <h3 style="margin-bottom:0;">{{cart.payment_types.name}}</h3>
                                        <strong>{{cart.transaction_fee.rate}}% + {{cart.transaction_fee.fee|currency}} is the qualified rate</strong>
                                    </th>
                                </tr>
                                </thead>
                                <tbody style="border: none;">
                                    <tr>
                                        <td><strong>Description</strong></td>
                                        <td class="align-right"><strong>Rate (%)</strong></td>
                                        <td class="align-right"><strong>Fee ($)</strong></td>
                                    </tr>
                                    <tr ng-repeat="p in acquiringPricing track by $index">
                                        <td>{{p.productName}}</td>
                                        <td class="align-right"><span>{{p.rateDefault}}</span></td>
                                        <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <div class="column-6">
                            <table class="table rates">
                                <thead>
                                <tr>
                                    <th colspan="3">
                                        <h3 style="margin-bottom:0;">Product Pricing</h3>
                                    </th>
                                </tr>
                                </thead>
                                <tbody style="border: none;">
                                    <tr>
                                        <td><strong>Description</strong></td>
                                        <td class="align-right"><strong>Rate (%)</strong></td>
                                        <td class="align-right"><strong>Fee ($)</strong></td>
                                    </tr>
                                    <tr ng-repeat="p in equipmentPricing track by $index">
                                        <td>{{p.productName}}</td>
                                        <td class="align-right"><span>{{p.rateDefault}}</span></td>
                                        <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                                    </tr>
                                </tbody>
                            </table>
                            <table class="table rates">
                                <thead>
                                <tr>
                                    <th colspan="3">
                                        <h3 style="margin-bottom:0;">Rates - Applies to all</h3>
                                    </th>
                                </tr>
                                </thead>
                                <tbody style="border: none;">
                                    <tr>
                                        <td><strong>Description</strong></td>
                                        <td class="align-right"><strong>Rate (%)</strong></td>
                                        <td class="align-right"><strong>Fee ($)</strong></td>
                                    </tr>
                                    <tr ng-repeat="p in globalPricing track by $index">
                                        <td>{{p.productName}}</td>
                                        <td class="align-right"><span>{{p.rateDefault}}</span></td>
                                        <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

The popup can be invoked, or shown on screen, using an on listener on the $("#view-fees-modal") id. This function makes calls to the fdService.getAcquiringPricingStorage(), fdService.getEquipmentPricingStorage() and fdService.getGlobalPricingStorage() methods depending on which type of pricing is selected and then shows the data on screen using the $scope.apply() function.

For this section, only the getAcquiringPricingStorage() is invoked.

JavaScript

JavaScript

This code can be found at
js/app/controllers/cart.js.

$("#view-fees-modal").on('show.bs.modal', function () {
  $scope.acquiringPricing = fdService.getAcquiringPricingStorage();
  console.log($scope.acquiringPricing)
  $scope.equipmentPricing = fdService.getEquipmentPricingStorage();
  $scope.globalPricing = fdService.getGlobalPricingStorage();
  if (!$scope.$$phase) {
    $scope.$apply();
  }
});

Next Steps

In this section we discussed the POST Pricing/Acquiring endpoint and how to retrieve pricing details. In the next section, we’ll discuss the POST Pricing/Global endpoint.

Next: Get Global Pricing Products.

Pricing/Global

Overview

How is “Global” pricing different from “Equipment” pricing?

Global pricing refers to the costs that the merchant incurs for each payment transaction. Equipment pricing refers to the costs that the merchant incurs for their point-of-sale system.

API: POST Pricing/Global

Check out the detailed API documentation of the POST Pricing/Global API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Now, we’ll need to display global pricing information for particular products.

The POST Pricing/Global API can be used to get the list of pricing products that apply to every merchant regardless of equipment purchased or qualifying criteria.

Example user interface displaying Global Pricing Example user interface displaying Acquiring Pricing

Frontend Example

There are two components to displaying the pricing data on screen. First, we need to display a transaction fee section with a button that indicates the user should click it. Second, we’ll need a popup that displays the relevant pricing information to the user in a clear dialog.

Let’s tackle the transaction fee section first.

In the below HTML snippet, we define a sample view to organize the basic structure of this transaction fee section (we briefly discussed this code in the previous Shopping Cart section).

Transaction Fee Section

HTML

This code can be found at
web/templates/cart.tpl.


<div ng-if="cart.payment_types || cart.transaction_products.length">
    <p class="sub cart-table-toggle" ng-click="transactionFee = !transactionFee">Transaction Fee <i ng-show="allowExpand" class="fa cart-table-toggle" ng-class="{'fa-chevron-down': !transactionFee, 'fa-chevron-up': transactionFee}"></i></p>
    <table class="cart-items" ng-show="transactionFee || !allowExpand">
        <tbody ng-if="cart.payment_types && !(cart.payment_types.groups && cart.payment_types.groups.length)">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">TBD</td>
            </tr>
        </tbody>
        <tbody>
        <tbody ng-repeat="g in cart.payment_types.groups track by $index" ng-if="cart.payment_types && cart.payment_types.groups && cart.payment_types.groups.length">
            <tr>
                <td>
                    <p><strong><p ng-show="!isProductsClickable()">{{cart.payment_types.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/processing/{{cart.payment_types.id}}">{{cart.payment_types.name}}</a> <span class="small">({{g.name}})</span></strong><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removePaymentTypes()">Remove</a></span></p>
                    <p ng-repeat="p in cart.payment_types.products track by $index">&nbsp;&bullet; {{p.name}} <a class="small link" ng-click="removeProcessing(p)" ng-show="isAllowEdit()">Remove</a></p>
                </td>
                <td class="align-right">{{g.rate}}% + {{g.fee|currency}}</td>
            </tr>
        </tbody>
        <tbody>
            <tr ng-repeat="p in cart.transaction_products track by $index">
                <td>
                <p><p ng-show="!isProductsClickable()">{{p.name}}</p><a ng-show="isProductsClickable()" class="link" ng-href="#/{{p.parentProduct.id ? 'family' : 'product'}}/{{p.parentProduct.id ? p.parentProduct.id : p.id}}">{{p.name}}</a><span ng-show="isAllowEdit()"> | <a class="small link" ng-click="removeTransactionProduct(p)">Remove</a></span></p>
                </td>


                <td class="align-right">
                <span ng-show="p.parentProduct.fee || p.parentProduct.rate">{{p.parentProduct.rate}}% + {{p.parentProduct.fee|currency}}</span><span ng-hide="p.parentProduct">TBD</span>
                </td>
            </tr>
        </tbody>
        <tbody ng-show="cart.payment_types.products">
            <tr>
                <td></td>
                <td class="align-right">
                    <div ng-show="cart.payment_types.products">
                        <p><a class="small link" data-toggle="modal" data-target="#view-fees-modal">View Details</a>
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
</div>

Pricing Popup

Next, we want to display the correct pricing data to our users. We display this data in a popup in our Demo Marketplace. The below HTML snippet defines the pricing popup we’ll be using in this section.


<div ng-controller="CartCtrl" class="modal fade include-detail-modal" tabindex="-1" role="dialog" id="view-fees-modal">
  <div class="vertical-alignment-helper">
    <div class="modal-dialog vertical-align-center">
      <div class="modal-content">
        <div class="modal-header">
          <a class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true"><i class="fa fa-times"></i></span></a>
          <h4 class="modal-title">Rates and Fees</strong></h4>
        </div>
        <div class="modal-body row">
          <div class="rates-details-modal">
            <div class="column-6">
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">{{cart.payment_types.name}}</h3>
                      <strong ng-show="cart.transaction_fee">{{cart.payment_types.groups[0].rate}}% + {{cart.payment_types.groups[0].fee|currency}} is the qualified rate</strong>
                    </th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <!--Card Present & Card Not Present placeholder-->
                  <tr ng-repeat="group in groupedPricingDetails | orderByParentOrder:'parentOrder' track by $index">
                    <td ng-if="group[0].cardPresentDiscountRates.length>=1 || group[0].cardNotPresentDiscountRates.length>=1" colspan=3>
                      <div>
                        <a class="link toggle-rates-children" ng-class="'toggle-rates-children'+$index" ng-click="grouping($index)">
                          <i class="fa fa-lg fa-angle-double-down"></i>
                        </a>
                        <strong>{{group[0].groupName}}</strong>
                        <!--card present-->
                        <table ng-if="group[0].cardPresentDiscountRates.length>=1" class="table rates rate-child rate-child{{$index}}" style="display:none; margin: 10px 0 0 0;">
                          <tbody>
                            <tr>
                              <td>
                                <a class="link toggle-rates-sub-children" ng-class="'toggle-rates-sub-children'+$index" ng-click="subgrouping($index)">
                                  <i class="fa fa-lg fa-angle-double-down"></i>
                                </a>
                                <strong> Card Present </strong>
                              </td>
                              <td class="align-right">{{group[0].rateDefault}}</td>
                              <td class="align-right">{{group[0].defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index" ng-repeat="product in group[0].cardPresentDiscountRates track by $index" style="display:none;">
                            <tr>
                              <td>{{product.productName}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                              <td class="align-right">{{product.defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                        <!--card present end-->
                        <!--card not present-->
                        <table ng-if="group[0].cardNotPresentDiscountRates.length>=1" class="table rates rate-child rate-child{{$index}}" style="display:none; margin: 10px 0 0 0;">
                          <tbody>
                            <tr>
                              <td>
                                <a class="link toggle-rates-sub-children" ng-class="'toggle-rates-sub-children'+$index + 'np'" ng-click="subgrouping($index + 'np')">
                                  <i class="fa fa-lg fa-angle-double-down"></i>
                                </a>
                                <strong> Card Not Present</strong>
                              </td>
                              <td>{{group[0].cardNotPresentDiscountRates[0].rateDefault}}</td>
                              <td>{{group[0].cardNotPresentDiscountRates[0].defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index + 'np'" ng-repeat="product in group[0].cardNotPresentDiscountRates track by $index" style="display:none;">
                            <tr>
                              <td>{{product.productName}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                              <td class="align-right">{{product.rateDefault}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                        <!--card not present end-->
                      </div>
                    </td>
                  </tr>
                  <!--Card Present & Card Not Present placeholder-->
                  <!--grouped discount rates products-->
                  <tr ng-repeat="items in groupedDiscountRates | orderByParentOrder:'parentOrder' track by $index">
                    <td colspan="3">
                      <div>
                        <a ng-if="items.length>=1" class="link toggle-rates-children+'gdr'" ng-class="'toggle-rates-children' + $index+'gdr'" ng-click="grouping($index+'gdr')">
                          <i class="fa fa-lg fa-angle-double-down"></i></a>
                        <strong>{{items[0].groupName}}</strong>
                        <table class="table rates rate-child rate-child{{$index+'gdr'}}" style="margin: 10px 0 0 0;display:none;">
                          <!--repeated part-->
                          <tbody class="rate-sub-child rate-sub-child+$index" ng-repeat="item in items track by $index">
                            <tr>
                              <td>{{item.productName}}</td>
                              <td class="align-right">{{item.rateDefault}}</td>
                              <td class="align-right">{{item.defaultAmt}}</td>
                            </tr>
                          </tbody>
                          <!--end repeated part-->
                        </table>
                      </div>
                    </td>
                  </tr>
                  <!--end grouped discount rates products-->
                  <tr ng-repeat="item in discountRates track by $index">
                    <td><strong>{{item.productName}}</strong></td>
                    <td class="align-right">{{item.rateDefault}}</td>
                    <td class="align-right">{{item.defaultAmt}}</td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="column-6">
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">Product Pricing</h3>
                    </th>
                  </tr>
                </thead>
                <tbody style="border: none;">
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <tr ng-repeat="p in equipmentPricing track by $index">
                    <td>{{p.productName}}</td>
                    <td class="align-right"><span>{{p.rateDefault}}</span></td>
                    <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                  </tr>
                </tbody>
              </table>
              <table class="table rates">
                <thead>
                  <tr>
                    <th colspan="3">
                      <h3 style="margin-bottom:0;">Rates - Applies to all</h3>
                    </th>
                  </tr>
                </thead>
                <tbody style="border: none;">
                  <tr>
                    <td><strong>Description</strong></td>
                    <td class="align-right"><strong>Rate (%)</strong></td>
                    <td class="align-right"><strong>Fee ($)</strong></td>
                  </tr>
                  <tr ng-repeat="p in globalPricing track by $index">
                    <td>{{p.productName}}</td>
                    <td class="align-right"><span>{{p.rateDefault}}</span></td>
                    <td class="align-right"><span>{{p.defaultAmt}}</span></td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

The popup can be invoked, or shown on screen, using an on listener on the $("#view-fees-modal") id. This function makes calls to the fdService.getAcquiringPricingStorage(), fdService.getEquipmentPricingStorage() and fdService.getGlobalPricingStorage() methods depending on which type of pricing is selected and then shows the data on screen using the $scope.apply() function.

For this section, only the getAcquiringGlobalStorage() is invoked.

JavaScript

JavaScript

This code can be found at
js/app/controllers/cart.js.

$("#view-fees-modal").on('show.bs.modal', function () {
  $scope.acquiringPricing = fdService.getAcquiringPricingStorage();
  console.log($scope.acquiringPricing)
  $scope.equipmentPricing = fdService.getEquipmentPricingStorage();
  $scope.globalPricing = fdService.getGlobalPricingStorage();
  if (!$scope.$$phase) {
    $scope.$apply();
  }
});

Next Steps

In this section we discussed thePOST Pricing/Global endpoint and how to retrieve pricing details. You should now have all pricing information. In the next section, we’ll initiate the process of placing an order.

Next: Place an Order if you already have a Shopping Cart.

Place Order

Overview

API: POST Application/Checkout

Check out the detailed API documentation of the POST Application/Checkout API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

What is an “Order”?

When a merchant visits your site they must first complete an order for their point-of-sale system (or other payment product). After this is completed, they can start the merchant application process.

You’ve made it this far! With all the information we’ve discussed so far, it’s finally time to place an order. First Data provides the POST Application/Checkout endpoint for just this purpose.

In this section, we’ll discuss how to use the checkout endpoint to make a purchase using our Demo Marketplace app.

The POST Application/Checkout API is used to place the order using input data from a form and products in the Shopping Cart.

Example user interface displaying the Place Order form and the Shopping Cart Example user interface displaying the Place Order form and the Shopping Cart

Frontend example

HTML

This code can be found at
web/templates/cart.tpl.

In the below HTML snippet, we define a sample view with a button called PlaceOrder. When clicked, this button will invoke the placeOrder() function and make a POST request to the /updateorder endpoint.

The below code is a section of the page containing the Place Order form and the Shopping Cart, used in placing the order via the POST Application/Checkout API.


<div ng-if="page == 'summary'">
  <a class="btn" ng-class="{'disabled': !orderId}" ng-click="placeOrder(showTrDetailBox)" ng-disabled="!orderId"><i ng-show="placeOrderInProgress" class="fa fa-spinner fa-spin fa-lg fa-fw"></i>Place Order</a>
</div>

When the Place Order button is clicked, the placeOrder() function is invoked, which internally gets the cart details and calls submitOrder() to submit the order and also makes a call to /updateorder endpoint using data collected from the user via forms and the Shopping Cart.

JavaScript

This code can be found at
web/app/services/service.js.

/**
     * submit / place order
     * @method submitOrder
     * @param cartDetails
     * @return {HTTPPromise}
*/
this.submitOrder = function(cartDetails) {
      var orderId = this.getOrderId();
      var cart = orderId ? this.getOrderedCart(orderId) : this.getCart();
      var ti = this.getTransactionInfo();
      var ap = this.getAcquiringPricingStorage();
      var ep = this.getEquipmentPricingStorage();
      var gp = this.getGlobalPricingStorage();

      var pricingDetails = [];
      var discountRates = ap.discountRates !== undefined ? ap.discountRates : [];
      ep = ep !== undefined ? ep : [];
      gp = gp !== undefined ? gp : [];

      pricingDetails = pricingDetails.concat(discountRates);
      pricingDetails = pricingDetails.concat(ep);
      pricingDetails = pricingDetails.concat(gp);

      var cardPresentDiscountRates = ap.cardPresentDiscountRates !== undefined ? ap.cardPresentDiscountRates : [];
      var cardNotPresentDiscountRates = ap.cardNotPresentDiscountRates !== undefined ? ap.cardNotPresentDiscountRates : [];

      if (!cartDetails) {
        var cartDetails = {
          data: [],
          amount: cart.amount,
          shipping_amount: cart.shipping_amount,
          tax: cart.tax,
          taxPercent: cart.taxPercent,
          total: cart.total,
          status: 0,
          monthly: [],
          shipping_option_id: cart.shipping_option_id,
          numberofLocations: cart.num_locations_selected,
          purchaseEnabled: true,
          total_qty: cart.total_qty,
        };

        for (var i in cart.data) {
          cartDetails.data.push({
            id: cart.data[i].id,
            name: cart.data[i].name,
            price: cart.data[i].price,
            monthly: [],
            term: cart.data[i].term,
            qty: cart.data[i].qty,
            category: cart.data[i].category,
            productType: cart.data[i].productType,
          });
        }

        //send Shipping details
        //var shippingMethods = this.getSessionShippingMethods();
        var shipProduct = CONST.SHIPPING_METHODS[cart.shipping_option_id];
        if (shipProduct !== undefined && (cart.amount > 0 || cart.lease_amount > 0)) {
          cartDetails.data.push({
            id: shipProduct.productId,
            name: shipProduct.productName,
            price: shipProduct.price,
            monthly: [],
            term: 'P',
            qty: 1,
            category: ti.category,
            productType: shipProduct.productType
          });
        }

        for (var i in cart.payment_types.products) {
          cartDetails.data.push({
            id: cart.payment_types.products[i].id,
            name: cart.payment_types.products[i].name,
            price: cart.payment_types.products[i].price,
            monthly: [],
            term: cart.payment_types.products[i].term,
            qty: cart.payment_types.products[i].qty,
            category: cart.payment_types.products[i].category,
            productType: cart.payment_types.products[i].type,
          });
        }

        for (var i in cart.transaction_products) {
          cartDetails.data.push({
            id: cart.transaction_products[i].id,
            name: cart.transaction_products[i].name,
            price: cart.transaction_products[i].price,
            monthly: [],
            term: cart.transaction_products[i].term,
            category: cart.transaction_products[i].category,
            qty: cart.transaction_products[i].qty,
            productType: cart.transaction_products[i].type,
          });
        }
      }

      var transactionInfo = {
        mccTypes: ti.mccTypes,
        mcc: ti.mcc,
        annualVolume: ti.annualVolume,
        creditCardVolume: ti.annualcardVolume,
        telecheckVolume: ti.telecheckVolume,
        averageTicket: ti.averageTicket,
        highestTicket: ti.highestTicket,
        category: ti.category,
        amexMemberId: ti.amexMemberId,
        amexVolume: ti.amexVolume,
      };

      var data = {
        orderId: orderId,
        company: cart.shippingAddress[0].company_name,
        first_name: cart.shippingAddress[0].firstname,
        last_name: cart.shippingAddress[0].lastname,
        email: cart.shippingAddress[0].email,
        phone: cart.shippingAddress[0].phone,
        address1: cart.shippingAddress[0].address1,
        city: cart.shippingAddress[0].city,
        state: cart.shippingAddress[0].state,
        zip: cart.shippingAddress[0].zip,
        recordType: 'Lead',
        pricingDetails: pricingDetails,
        cardPresentDiscountRates: cardPresentDiscountRates,
        cardNotPresentDiscountRates: cardNotPresentDiscountRates,
        pricingOptions: {
          transactionInfo: transactionInfo,
        },
        shippingAddress: cart.shippingAddress,
        cardNotPresent: cart.cardNotPresent,
        cartDetails: cartDetails
      };

      return $http.post(urlPrefix + '/marketplace/v1/merchantorders/' + orderId + '/updateorder', data);
    };


Next Steps

In this section we discussed the POST Application//updateorder endpoint and how to invoke this endpoint when the checkout button is clicked. In the next section, we’ll display Order Confirmation to our users if the checkout is successful.

Next: Display the Order Confirmation page with instructions on the next steps (Optional).

Skip To: Sign up merchants using the online Merchant Application.

Order Confirmation

Overview

Now that we’ve successfully placed an order using the First Data Marketplace APIs, let’s display a confirmation page to our users indicating a successful transaction.

While we do not have an API for Order Confirmation, we suggest displaying this information in an HTML view.

In this section, we’ll set up a basic HTML view to display on screen.

What should be displayed for Order Confirmation?

We recommend that you include a link to the Merchant Application form on your Confirmation page.

However, you can display any content you would like.

Example user interface displaying the Order Confirmation page Example user interface displaying Order Confirmation

Frontend example

The below code is an example of the Order Confirmation page.

As you can see, this is a simple, static HTML page that displays the order’s status as “Pending”. Since we do not currently have an API for Order Confirmation, this static content serves in its place.

<div id="breadcrumb-anchor"></div>
<div id="breadcrumb" breadcrumb>
  <div class="breadcrumb-inner container">
    <div class="breadcrumb-mobile">
      <a id="mobile-breadcrumb-toggle"><i class="fa fa-chevron-down"></i> <span>Thank You</span></a>
    </div>
    <ul>
      <li><a>Select Signup</a></li>
    </ul>
  </div>
</div>
<div class="main-content">
  <section>
    <div class="container">
      <div class="column-8 checkout-form">
        <h1>
            <span class="fa-stack" style="color: green; font-size: 55%;">
            <i class="fa fa-circle-thin fa-stack-2x"></i>
                <i class="fa fa-exclamation fa-stack-1x"></i>
            </span>
            You're almost done...
        </h1>
        <br>
        <h3>Order is<strong> PENDING</strong>.</h3>
        <br>
        <p>A First Data Processing Plan is required. You will not receive your order until you have completed the signup process. Payment information will be captured as part of the sign up process.</p>
        <div class="form-group form-actions">
          <div class="column-8" style="padding-left:0;">
            <a class="button submit" ng-href="#/signup">Sign Up</a>
            <br><br><br>
            <a class="link-blue" href="#/">Back to First Data</a>
          </div>
        </div>
      </div>
      <ng-include src="'templates/cart.tpl'"></ng-include>
    </div>
  </section>

</div><!-- end .content -->

Next Steps

In this section we discussed how to display an order status to our users. In the next section, we’ll discuss the merchant information endpoint.

Awesome! You now have a complete shopping experience.

Next: Sign up merchants using the online Merchant Application.

Merchant Application

Overview

API: POST Application/Update

Check out the detailed API documentation of the POST Application/Update API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

The application process is used to determine the merchant’s eligibility for a payment processing account. The Merchant Application form collects all the necessary information, such as owner and business information, estimated transaction volumes and bank details (for ACH deposits once approved).

Below are the necessary steps you need to follow for a merchant to process credit cards on First Data.

Example user interface displaying the Merchant Application form Example user interface displaying Merchant Application form

Frontend example

In the below HTML snippet, we’ve defined a signup view to display the Merchant Application form.

This form gathers merchant-related information. It invokes the formSubmit() function when the user is finished.

<div id="breadcrumb-anchor"></div>
<div id="breadcrumb" breadcrumb>
    <div class="breadcrumb-inner container">
        <div class="breadcrumb-mobile">
            <a id="mobile-breadcrumb-toggle" class="current"><i class="fa fa-chevron-down"></i> <span>Merchant Application</span></a>
        </div>
        <ul>
            <li><a class="current">Merchant Application</a></li>
            <li><a style="color:#aaa;">Location Setup</a></li>
            <li><a style="color:#aaa;">Merchant Agreement</a></li>
            <li><a style="color:#aaa;">Finish</a></li>
        </ul>
    </div>
</div>

<style>div.error{display:block}</style>
<div id="signup-content" class="main-content">
    <form name="signupForm" novalidate style="max-width:100%" autocomplete="off" id="signupForm">
        <div class="container">
            <h1 class="align-center" style="margin-top:20px">Let's sign you up.</h1>
            <p class="align-center subhead "> Signing up for First Data Solutions is fast and free!
                <br/>
                <span class="small">Please note that the transaction fees offered apply only if you complete this application online process and your application is approved.
        </span>
            </p>
            <p id="form-error" ng-show="form_error">Your form cannot be submitted. Please check the fields highlighted in red. Make sure all fields are completed and your information is correct.</p>
            <p id="form-error" ng-if="tinError && formData.HOW_BUSINESS_FILES_TAXES == 'business_tax_id'">Tax filing name does not match EIN. If this is in error please disregard and select continue.</p>
            <p id="form-error" ng-if="tinError && formData.HOW_BUSINESS_FILES_TAXES != 'business_tax_id'">Tax filing name does not match SSN. If this is in error please disregard and select continue.</p>
            <br>
            <div class="form-group" style="clear:both">
                <h2>Tell us about the business.</h2>
                <div class="column-6">
                    <div class="form-element">
                        <label class="fancy-field"  fancy-field  ng-class="{'error': (signupForm.DBA_NAME.$touched && signupForm.DBA_NAME.$invalid) || tinError}">
                            <input type="text" placeholder="DBA Name" ng-model="formData.DBA_NAME" ng-pattern="dbaNamePattern" name="DBA_NAME" required="required" minlength="2" maxlength="24" />
                        </label>
                        <p ng-show="signupForm.DBA_NAME.$touched && signupForm.DBA_NAME.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter your DBA Name.</p>
                        <p ng-show="signupForm.DBA_NAME.$touched && signupForm.DBA_NAME.$error.minlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Business name must be of at least 2 characters.</p>
                        <p ng-show="signupForm.DBA_NAME.$touched && signupForm.DBA_NAME.$error.maxlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Business name must be less than 25 characters.</p>
                        <p ng-show="signupForm.DBA_NAME.$touched && signupForm.DBA_NAME.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Special characters( {, } , |, ~ ) are not allowed.</p>
                        <p ng-show="tinError && formData.HOW_BUSINESS_FILES_TAXES == 'business_tax_id'" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Name does not match EIN.</p>
                        <p ng-show="tinError && formData.HOW_BUSINESS_FILES_TAXES != 'business_tax_id'" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Name does not match SSN.</p>
                    </div>
                    <div class="form-element">
                        <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.LEGAL_BUSINESS_NAME_SAME_AS_DBA.$touched && signupForm.LEGAL_BUSINESS_NAME_SAME_AS_DBA.$invalid}">
                            <select placeholder="Is the legal business name the same as the DBA name?" ng-model="formData.LEGAL_BUSINESS_NAME_SAME_AS_DBA" name="LEGAL_BUSINESS_NAME_SAME_AS_DBA" id="LEGAL_BUSINESS_NAME_SAME_AS_DBA" required="required">
                                <option value="">Is the legal business name the same as the DBA name?</option>
                                <option value="1">Yes</option>
                                <option value="0">No</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.LEGAL_BUSINESS_NAME_SAME_AS_DBA.$touched && signupForm.LEGAL_BUSINESS_NAME_SAME_AS_DBA.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select any option.</p>
                    </div>
                    <div class="form-element" ng-if="formData.LEGAL_BUSINESS_NAME_SAME_AS_DBA == 0" >
                        <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.legal_business_name.$touched && signupForm.legal_business_name.$invalid}">
                            <input type="text" placeholder="Legal Business Name" minlength="2" maxlength="24" ng-model="formData.legal_business_name" name="legal_business_name" ng-pattern="dbaNamePattern" ng-required="true" />
                        </label>
                        <p ng-show="signupForm.legal_business_name.$touched && signupForm.legal_business_name.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter Legal Name of your business.</p>
                        <p ng-show="signupForm.legal_business_name.$touched && signupForm.legal_business_name.$error.minlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Business name must be of at least 2 characters.</p>
                        <p ng-show="signupForm.legal_business_name.$touched && signupForm.legal_business_name.$error.maxlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Business name must be less than 25 characters.</p>
                        <p ng-show="signupForm.legal_business_name.$touched && signupForm.legal_business_name.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Special characters( {, } , |, ~ ) are not allowed.</p>

                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME.$touched && signupForm.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME.$invalid}">
                            <select placeholder="Is the tax filing name the same as your business legal name?" ng-model="formData.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME" name="TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME" required="required">
                                <option value="">Is the tax filing name the same as your business legal name?</option>
                                <option value="1">Yes</option>
                                <option value="0">No</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME.$touched && signupForm.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select any option.</p>
                    </div>
                    <div class="form-element" ng-if="formData.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME == 0" >
                        <label class="fancy-field"  fancy-field ng-class="{'error': (signupForm.tax_filing_name.$touched && signupForm.tax_filing_name.$invalid) || tinError}">
                            <input type="text" placeholder="Tax Filing Name" ng-pattern="dbaNamePattern" ng-model="formData.tax_filing_name" name="tax_filing_name" minlength="2" maxlength="40" ng-required="true" />
                        </label>
                        <p ng-show="signupForm.tax_filing_name.$touched && signupForm.tax_filing_name.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter Tax Filing Name of your business.</p>
                        <p ng-show="signupForm.tax_filing_name.$touched && signupForm.tax_filing_name.$error.minlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Tax filing name must be of at least 2 characters.</p>
                        <p ng-show="signupForm.tax_filing_name.$touched && signupForm.tax_filing_name.$error.maxlength" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Tax filing name must be less than 41 characters.</p>
                        <p ng-show="signupForm.tax_filing_name.$touched && signupForm.tax_filing_name.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Special characters( {, } , |, ~ ) are not allowed.</p>
                        <p ng-show="tinError && formData.HOW_BUSINESS_FILES_TAXES == 'business_tax_id'" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Name does not match EIN.</p>
                        <p ng-show="tinError && formData.HOW_BUSINESS_FILES_TAXES != 'business_tax_id'" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Name does not match SSN.</p>
                    </div>
                    <div class="form-element">
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.HOW_BUSINESS_FILES_TAXES.$touched && signupForm.HOW_BUSINESS_FILES_TAXES.$invalid}">
                            <select placeholder="How does this business file taxes?" id="files-taxes" ng-model="formData.HOW_BUSINESS_FILES_TAXES" name="HOW_BUSINESS_FILES_TAXES" required="required">
                                <option value="">How does this business file taxes?</option>
                                <option value="owner_ssn">By owner's Social Security Number</option>
                                <option value="business_tax_id">By Business Federal Tax ID (EIN)</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.HOW_BUSINESS_FILES_TAXES.$touched && signupForm.HOW_BUSINESS_FILES_TAXES.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select any option.</p>
                    </div>
                    <div class="form-element" ng-if="formData.HOW_BUSINESS_FILES_TAXES == 'business_tax_id'">
                        <label class="fancy-field"  fancy-field  ng-class="{'error': (signupForm.EIN.$touched && signupForm.EIN.$invalid) || tinError}">
                            <input type="text" placeholder="EIN Number" name="EIN" ng-model="formData.EIN" ng-pattern="einPattern" maxlength="9" ng-required="true"/>
                        </label>
                        <p ng-show="signupForm.EIN.$touched && signupForm.EIN.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Update tax identification number .</p>
                        <p ng-show="signupForm.EIN.$touched && signupForm.EIN.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Employer identification number must be a 9 digit number .</p>
                        <p ng-show="signupForm.EIN.$error.excluded" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Not a valid Employer identification number.</p>
                        <p ng-show="tinError" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> EIN does not match Tax filing name.</p>
                    </div>
                    <div class="form-element">
                        <div class="column-4" style="padding:0 8px 0 0;">
                            <label class="fancy-field" fancy-field ng-class="{'error': (signupForm.YEAR_BUSINESS_STARTED.$touched && signupForm.YEAR_BUSINESS_STARTED.$invalid) || (signupForm.MONTH_BUSINESS_STARTED.$touched && signupForm.MONTH_BUSINESS_STARTED.$invalid)}">
                                <select placeholder="Yr. business started" ng-model="formData.YEAR_BUSINESS_STARTED" name="YEAR_BUSINESS_STARTED" required="required" ng-min="1950" ng-change="checkBsnMo()">
                                    <option value="">Yr. business started</option>
                                    <option ng-repeat="y in [] | range:thisYear:1900" ng-value="y">{{y}}</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.YEAR_BUSINESS_STARTED.$touched && signupForm.YEAR_BUSINESS_STARTED.$error.required ||  (signupForm.MONTH_BUSINESS_STARTED.$touched && signupForm.MONTH_BUSINESS_STARTED.$error.required)" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Select the year and month of your business started .</p>
                            <p ng-show="signupForm.YEAR_BUSINESS_STARTED.$touched && signupForm.YEAR_BUSINESS_STARTED.$error.min" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter a year past 1950 .</p>
                            <p ng-show="signupForm.MONTH_BUSINESS_STARTED.$touched && signupForm.MONTH_BUSINESS_STARTED.$error.excluded" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Date cannot be future date .</p>
                        </div>
                        <div class="column-4" style="padding:0;">
                            <label class="fancy-field" for="MONTH_BUSINESS_STARTED" fancy-field ng-class="{'error': (signupForm.YEAR_BUSINESS_STARTED.$touched && signupForm.YEAR_BUSINESS_STARTED.$invalid) || (signupForm.MONTH_BUSINESS_STARTED.$touched && signupForm.MONTH_BUSINESS_STARTED.$invalid)}">
                                <select placeholder="Mo. business started" id="MONTH_BUSINESS_STARTED" ng-model="formData.MONTH_BUSINESS_STARTED" name="MONTH_BUSINESS_STARTED" required="required" ng-change="checkBsnMo()">
                                    <option value="">Mo. business started</option>
                                    <option value="01">January</option>
                                    <option value="02">February</option>
                                    <option value="03">March</option>
                                    <option value="04">April</option>
                                    <option value="05">May</option>
                                    <option value="06">June</option>
                                    <option value="07">July</option>
                                    <option value="08">August</option>
                                    <option value="09">September</option>
                                    <option value="10">October</option>
                                    <option value="11">November</option>
                                    <option value="12">December</option>
                                </select>
                            </label>

                        </div>
                        <div class="column-4" style="padding:0 0 0 8px;">
                            <label class="fancy-field"  fancy-field ng-class="{'error': (signupForm.INCORPORATION_STATE.$touched && signupForm.INCORPORATION_STATE.$invalid)}">
                                <select placeholder="State of incorporation" ng-model="formData.INCORPORATION_STATE" name="INCORPORATION_STATE" required="required">
                                    <option value="">State of incorporation</option>
                                    <option ng-repeat="states in CONST.STATES" ng-value="states.abbr">{{states.name}}</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.INCORPORATION_STATE.$touched && signupForm.INCORPORATION_STATE.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> State where business was formed.</p>
                        </div>
                    </div>
                    <div class="form-element">
                        <label class="fancy-field" fancy-field  ng-class="{'error': signupForm.ORGANIZATION_TYPE.$touched && signupForm.ORGANIZATION_TYPE.$invalid}">
                            <select placeholder="Organization type" ng-model="formData.ORGANIZATION_TYPE" name="ORGANIZATION_TYPE" required="required">
                                <option value="">Select Organization type</option>
                                <option value="I">Sole Proprietorship</option>
                                <option value="P">Partnerships</option>
                                <option value="C">Public Corporation</option>
                                <option value="PRC">Private Corporation</option>
                                <option value="L">Limited Liability Company (LLC)</option>
                                <option value="T">Tax Exempt</option>
                                <option value="G">Government</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.ORGANIZATION_TYPE.$touched && signupForm.ORGANIZATION_TYPE.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select the business organization type.</p>
                    </div>
                    <div class="form-element">
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.businesstype.$touched && signupForm.businesstype.$invalid}">
                            <input type="text" placeholder="Business phone number" format-phone ng-model="formData.businessPhone" ng-pattern="phoneNumberPattern" name="businesstype" maxlength="14" required="required"/>
                        </label>
                        <p ng-show="signupForm.businesstype.$touched && signupForm.businesstype.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter business phone number.</p>
                        <p ng-show="signupForm.businesstype.$touched && signupForm.businesstype.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter a valid phone number.</p>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.BUSINESS_WEBSITE.$touched && signupForm.BUSINESS_WEBSITE.$invalid}">
                            <input type="text" placeholder="Business Website" ng-model="formData.BUSINESS_WEBSITE" ng-pattern="urlPattern" name="BUSINESS_WEBSITE" maxlength="70" ang-web-validate internet="formData.INTERNET_PAY"  ng-required="formData.INTERNET_PAY > 0 && categoryDetails.name=='ECOMMERCE'"/>
                        </label>
                        <p ng-show="signupForm.BUSINESS_WEBSITE.$touched && signupForm.BUSINESS_WEBSITE.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter website address.
                        </p>
                        <p ng-show="signupForm.BUSINESS_WEBSITE.$touched && signupForm.BUSINESS_WEBSITE.$error.WebValidate" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Required when Internet % is greater than 0.
                        </p>
                        <p ng-show="signupForm.BUSINESS_WEBSITE.$touched && signupForm.BUSINESS_WEBSITE.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Not a valid website address.</p>
                        <p ng-show=" signupForm.BUSINESS_WEBSITE.$invalid && formData.INTERNET_PAY > 0 && categoryDetails.name=='ECOMMERCE'" class="form-error-detail">
                            <i class="fa fa-info-circle"></i>Business Website address required when internet % is greater than 0% for E-Commerce merchants.</p>
                    </div>
                </div>
                <div class="column-6">
                    <div class="form-element">
                        <p>How do you plan to accept payments? <br><span class="small">(Must total 100%)</span></p>
                        <div class="column-4" style="padding: 5px 8px 0 0">
                            <label class="fancy-field" for="facetoface" fancy-field ng-class="{'error': (signupForm.FACE_TO_FACE.$touched && signupForm.FACE_TO_FACE.$invalid) || (signupForm.PHONE_OR_EMAIL.$touched && signupForm.PHONE_OR_EMAIL.$invalid) || (signupForm.INTERNET_PAY.$touched && signupForm.INTERNET_PAY.$invalid)}">
                                <select placeholder="Face to face" id="facetoface" name="FACE_TO_FACE" required="required" ng-model="formData.FACE_TO_FACE" ng-change="faceToFaceChange(0)">
                                    <option value="">Face to face</option>
                                    <option ng-repeat="val in percentValues" value="{{val}}">{{val}}%</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.FACE_TO_FACE.$touched && signupForm.FACE_TO_FACE.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Total must be 100%.</p>
                        </div>
                        <div class="column-4" style="padding: 5px 8px 0 0;">
                            <label class="fancy-field" for="phoneoremail" fancy-field  ng-class="{'error': (signupForm.PHONE_OR_EMAIL.$touched && signupForm.PHONE_OR_EMAIL.$invalid) || (signupForm.FACE_TO_FACE.$touched && signupForm.FACE_TO_FACE.$invalid) || (signupForm.INTERNET_PAY.$touched && signupForm.INTERNET_PAY.$invalid)}">
                                <select placeholder="Phone/mail order" id="phoneoremail" name="PHONE_OR_EMAIL" required="required" ng-model="formData.PHONE_OR_EMAIL" ng-change="faceToFaceChange(1)">
                                    <option value="">Phone/mail order</option>
                                    <option ng-repeat="val in percentValues" value="{{val}}">{{val}}%</option>
                                </select>
                            </label>

                            <p ng-show="signupForm.PHONE_OR_EMAIL.$touched && signupForm.PHONE_OR_EMAIL.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Total must be 100%.</p>
                        </div>

                        <div class="column-4" style="padding: 5px 0px 0 0;">
                            <label class="fancy-field" for="internetPay" fancy-field  ng-class="{'error': (signupForm.INTERNET_PAY.$touched && signupForm.INTERNET_PAY.$invalid) || (signupForm.FACE_TO_FACE.$touched && signupForm.FACE_TO_FACE.$invalid) || (signupForm.PHONE_OR_EMAIL.$touched && signupForm.PHONE_OR_EMAIL.$invalid)}">
                                <select placeholder="Internet" id="internetPay" name="INTERNET_PAY" required="required" ng-model="formData.INTERNET_PAY" ng-change="faceToFaceChange(2)">
                                    <option value="">Internet</option>
                                    <option ng-repeat="val in percentValues" value="{{val}}">{{val}}%</option>
                                </select>
                            </label>

                            <p ng-show="signupForm.INTERNET_PAY.$touched && signupForm.INTERNET_PAY.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Total must be 100%.</p>
                        </div>
                        <p ng-show="signupForm.PHONE_OR_EMAIL.$error.size" class="form-error-detail">
                            <i class="fa fa-info-circle"></i>Either Phone/Mail Order or Internet payments should be greater than 80% for E-Commerce merchants.</p>
                        <p ng-show="signupForm.PHONE_OR_EMAIL.$error.total" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Total must be 100%.</p>

                    </div>
                    <div class="form-element" >
                        <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.TYPICAL_SALE_AMOUNT.$touched && signupForm.TYPICAL_SALE_AMOUNT.$invalid}">
                            <input type="number" placeholder="Typical sale amount" ng-model="formData.TYPICAL_SALE_AMOUNT" name="TYPICAL_SALE_AMOUNT" min="1" max="9999.99" required="required" maxlength="50" />
                        </label>
                        <p ng-show="signupForm.TYPICAL_SALE_AMOUNT.$touched && signupForm.TYPICAL_SALE_AMOUNT.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter typical sale amount.</p>
                        <p ng-show="signupForm.TYPICAL_SALE_AMOUNT.$touched && signupForm.TYPICAL_SALE_AMOUNT.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Numeric characters only.</p>
                        <p ng-show="signupForm.TYPICAL_SALE_AMOUNT.$touched && signupForm.TYPICAL_SALE_AMOUNT.$invalid" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Typical sale amount cannot be Higher than 9999.99 and lower than 1.</p>
                    </div>
                    <div class="form-element">
                        <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$touched && signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$invalid}">
                            <input type="number" placeholder="Anticipated highest ticket sale" ng-model="formData.ANTICIPATED_HIGHEST_TICKET_SALE" name="ANTICIPATED_HIGHEST_TICKET_SALE" min="{{formData.TYPICAL_SALE_AMOUNT +1}}" maxlength="50" required="required" />
                        </label>
                        <p ng-show="signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$touched && signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter anticipated highest ticket sale amount.</p>
                        <p ng-show="signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$touched && signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Numeric characters only.</p>
                        <p ng-show="signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$touched && signupForm.ANTICIPATED_HIGHEST_TICKET_SALE.$invalid" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Highest Ticket cannot be lower than Average Ticket.</p>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.annualVolume.$touched && signupForm.annualVolume.$invalid}">
                            <input type="text" placeholder="Anticipated annual credit card sales" ng-model="formData.annualVolume" name="annualVolume" readonly>
                        </label>
                        <p ng-show="signupForm.annualVolume.$touched && signupForm.annualVolume.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select anticipated annual sales.</p>
                    </div>
                    <div class="form-element multiple">
                        <p>Primary Business Address</p>
                        <label class="fancy-field"  fancy-field style="margin-bottom: 8px;" ng-class="{'error': (signupForm.business_address1.$touched && signupForm.business_address1.$invalid) || (signupForm.business_address1.$touched && signupForm.business_address1.$invalid)}">
                            <input type="text" placeholder="Business street address" ng-maxlength="24" maxlength="24" ng-pattern="streetAddressPattern" ng-model="formData.business_address1" name="business_address1" ng-required="true"/>
                        </label>
                        <p ng-show="signupForm.business_address1.$touched && signupForm.business_address1.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter owner's street address.</p>
                        <p ng-show="signupForm.business_address1.$touched && signupForm.business_address1.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Special characters( {, } , |, ~ ) are not allowed.</p>
                        <label class="fancy-field" fancy-field style="margin-bottom: 8px;">
                            <input type="text" placeholder="Business Unit, Apt, Suite etc. (optional)"  ng-pattern="apartmentPattern" maxlength="24" ng-model="formData.business_address2" name="business_address2" />
                        </label>
                        <p ng-show="signupForm.business_address2.$touched && signupForm.business_address2.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Street Address cannot contain []<>%$+.</p>
                        <label class="fancy-field" fancy-field style="margin-bottom: 8px;" ng-class="{'error': signupForm.business_address_zip.$touched && signupForm.business_address_zip.$invalid}">
                            <input type="text" ng-change="lookupBusinessZip()" placeholder="Business ZIP"  maxlength="5" ng-model="formData.business_address_zip" ng-pattern="zipPattern" name="business_address_zip" ng-required="true" />
                        </label>
                        <p ng-show="signupForm.business_address_zip.$dirty && signupForm.business_address_zip.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter zip code.</p>
                        <p ng-show="signupForm.business_address_zip.$dirty && signupForm.business_address_zip.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter valid zip code.</p>
                        <label class="fancy-field"  fancy-field style="margin-bottom: 8px;" ng-class="{'error': signupForm.business_address_city.$touched && signupForm.business_address_city.$invalid}">
                            <input placeholder="City" type="text" ng-model="formData.business_address_city" name="business_address_city"  ng-pattern ="cityPattern" maxlength="32" required="required" />
                        </label>
                        <p ng-show="signupForm.business_address_city.$touched && signupForm.business_address_city.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter city.</p>
                        <p ng-show="signupForm.business_address_city.$touched && signupForm.business_address_city.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Invalid city.</p>
                        <label class="fancy-field" fancy-field  ng-class="{'error': signupForm.business_address_state.$touched && signupForm.business_address_state.$invalid}">
                            <select placeholder="State" ng-model="formData.business_address_state" name="business_address_state" required="required" ng-options="state.abbr as state.name for state in CONST.STATES">
                                <option value="">State</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.business_address_state.$touched && signupForm.business_address_state.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Select state.</p>

                    </div>

                </div>
            </div>
            <br>
            <div class="form-group">
                <h2>Tell us about the owner.</h2>
                <div class="column-6">
                    <div class="form-element" >
                        <div class="column-8" style="padding-left:0; padding-bottom:0;  padding-top:0; padding-bottom:0;padding-right: 0px;">
                            <label class="fancy-field" for="name" fancy-field ng-class="{'error': (signupForm.name.$touched && signupForm.name.$invalid)}">
                                <input type="text" id="name" placeholder="Full Name" ng-model="formData.name" name="name" ng-pattern="fullNamePattern" maxlength="49" required="required" />
                            </label>
                            <p ng-show="signupForm.name.$touched && signupForm.name.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter Full Name.</p>
                            <p ng-show="signupForm.name.$touched && signupForm.name.$error.pattern" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter in First and Last name format.</p>
                        </div>
                        <div class="column-4" style="padding-left:8px; padding-top:0; padding-bottom:0; padding-right: 0px;">
                            <label class="fancy-field" for="title1" fancy-field ng-class="{'error': signupForm.title1.$touched && signupForm.title1.$invalid}">
                                <select id="title1" placeholder="Title" ng-model="formData.title1" name="title1" required="required">
                                    <option value="">Title</option>
                                    <option ng-repeat="t in titles" value="{{ t }}">{{ t }}</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.title1.$touched && signupForm.title1.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Select your title.</p>
                        </div>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" for="phone" fancy-field ng-class="{'error': signupForm.phone.$touched && signupForm.phone.$invalid}">
                            <input type="text" id="phone" format-phone  placeholder="Phone Number" ng-model="formData.phone" ng-pattern="phoneNumberPattern" name="phone" required="required" maxlength="14" />
                        </label>
                        <p ng-show="signupForm.phone.$touched && signupForm.phone.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter phone number.</p>
                        <p ng-show="signupForm.phone.$touched && signupForm.phone.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter valid phone number.</p>
                    </div>
                    <div class="form-element" >
                        <div class="column-4" style="padding-left:0; padding-bottom:0; padding-top:0;">
                            <label class="fancy-field" for="dob_month" fancy-field ng-class="{'error': (signupForm.dob_month.$touched && signupForm.dob_month.$invalid) || (signupForm.dob_day.$touched && signupForm.dob_day.$invalid) || (signupForm.dob_year.$touched && signupForm.dob_year.$invalid)}">
                                <select name="dob_month" placeholder="DOB Month" id="dob_month" ng-model="dob_month" required="required" >
                                    <option value="">DOB Month</option>
                                    <option ng-repeat="m in [] | range:01:12" ng-value="m | numberFixedLen:2" >{{m|monthName}}</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.dob_month.$touched && signupForm.dob_month.$error.required || signupForm.dob_day.$touched && signupForm.dob_day.$error.required ||  signupForm.dob_year.$touched && signupForm.dob_year.$error.required " class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter date of birth.</p>
                        </div>
                        <div class="column-4" style="padding:0;">
                            <label class="fancy-field" for="dob_day" fancy-field ng-class="{'error': (signupForm.dob_month.$touched && signupForm.dob_month.$invalid) || (signupForm.dob_day.$touched && signupForm.dob_day.$invalid) || (signupForm.dob_year.$touched && signupForm.dob_year.$invalid)}">
                                <select name="dob_day" placeholder="DOB Day" id="dob_day" ng-model="dob_day" required="required">
                                    <option value="">DOB Day</option>
                                    <option ng-repeat="d in [] | range:01:31" ng-value="d | numberFixedLen:2">{{d}}</option>
                                </select>
                            </label>
                        </div>
                        <div class="column-4" style="padding-right:0; padding-bottom:0; padding-top:0;">
                            <label class="fancy-field" for="dob_year" fancy-field ng-class="{'error': (signupForm.dob_month.$touched && signupForm.dob_month.$invalid) || (signupForm.dob_day.$touched && signupForm.dob_day.$invalid) || (signupForm.dob_year.$touched && signupForm.dob_year.$invalid)}">
                                <select id="dob_year" placeholder="DOB Year" name="dob_year" ng-model="dob_year" required="required">
                                    <option value="">DOB Year</option>
                                    <option ng-repeat="y in [] | range:thisYear-18:1900" ng-value="y">{{y}}</option>
                                </select>
                            </label>
                        </div>
                    </div>

                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.email.$touched && signupForm.email.$invalid}">
                            <input type="email" placeholder="Email Address" ng-model="formData.email" name="email" ng-pattern="emailPattern" required="required" maxlength="80" />
                        </label>
                        <p ng-show="signupForm.email.$touched && signupForm.email.$error.required" class="form-error-detail"><i class="fa fa-info-circle"></i> Enter email address.</p>
                        <p ng-show="signupForm.email.$touched && signupForm.email.$error.pattern" class="form-error-detail"><i class="fa fa-info-circle"></i> Please enter a valid email format(xyz@firstdata.com).</p>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': (signupForm.SocialSecurityNumber.$touched && signupForm.SocialSecurityNumber.$invalid)  || tinError}">
                            <input type="text" ssn-field ssn-field-mask="false" placeholder="SSN" ng-model="formData.SocialSecurityNumber" ng-pattern="ssnPattern" name="SocialSecurityNumber" required="required" maxlength="11" />
                        </label>
                        <p ng-show="signupForm.SocialSecurityNumber.$touched && signupForm.SocialSecurityNumber.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter Social Security Number.</p>
                        <p ng-show="signupForm.SocialSecurityNumber.$touched && signupForm.SocialSecurityNumber.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter a valid Social Security Number.</p>
                        <p ng-show="signupForm.SocialSecurityNumber.$error.excluded" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Not a valid Social Security Number.</p>
                        <p ng-show="tinError" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> SSN does not match Tax filing name.</p>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" for="Foreign_Ownership" fancy-field ng-class="{'error': signupForm.FOREIGN_OWNERSHIP.$touched && signupForm.FOREIGN_OWNERSHIP.$invalid}">
                            <select name="FOREIGN_OWNERSHIP" placeholder="For tax reporting purposes are you either of the following?" id="Foreign_Ownership" ng-model="formData.FOREIGN_OWNERSHIP" required="required">
                                <option value="">For tax reporting purposes are you either of the following?</option>
                                <option value="A">A foreign person</option>
                                <option value="A">A business that can claim foreign entity status</option>
                                <option value="N">None</option>
                            </select>
                        </label>
                        <p ng-show="signupForm.FOREIGN_OWNERSHIP.$touched && signupForm.FOREIGN_OWNERSHIP.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Please select one of the 3 options.</p>
                    </div>
                </div>
                <div class="column-6">
                    <div class="form-element multiple">
                        <div class="form-element" >
                            <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.Address1.$touched && signupForm.Address1.$invalid}">
                                <input type="text" placeholder="Street Address" ng-model="formData.Address1" ng-pattern="streetAddressPattern" name="Address1" required="required" maxlength="24" />
                            </label>
                            <p ng-show="signupForm.Address1.$touched && signupForm.Address1.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter street address.</p>
                            <p ng-show="signupForm.Address1.$touched && signupForm.Address1.$error.pattern" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Special characters( {, } , |, ~ ) are not allowed.</p>
                        </div>
                        <div class="form-element" >
                            <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.Address2.$touched && signupForm.Address2.$invalid}">
                                <input type="text" placeholder="Unit, Apt, Suite etc. (optional)" ng-model="formData.Address2" ng-pattern="apartmentPattern" name="Address2" maxlength="24" />
                            </label>
                            <p ng-show="signupForm.Address2.$touched && signupForm.Address2.$error.pattern" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Street Address cannot contain []<>%$+.</p>
                        </div>
                        <div class="form-element" >
                            <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.zip.$touched && signupForm.zip.$invalid}">
                                <input type="text" placeholder="ZIP" ng-change="lookupZip()" ng-model="formData.zip" name="zip"  ng-pattern ="zipPattern" required="required" maxlength="5" />
                            </label>
                            <p ng-show="signupForm.zip.$touched && signupForm.zip.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter zip code.</p>
                            <p ng-show="signupForm.zip.$touched && signupForm.zip.$error.pattern" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter valid zip code.</p>
                        </div>
                        <div class="form-element" >
                            <label class="fancy-field"  fancy-field ng-class="{'error': signupForm.city.$touched && signupForm.city.$invalid}">
                                <input placeholder="City" type="text" ng-model="formData.city" name="city"  ng-pattern ="cityPattern" maxlength="32" required="required" />
                            </label>
                            <p ng-show="signupForm.city.$touched && signupForm.city.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Enter city.</p>
                            <p ng-show="signupForm.city.$touched && signupForm.city.$error.pattern" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Invalid city.</p>
                        </div>
                        <div class="form-element">
                            <label class="fancy-field" fancy-field  ng-class="{'error': signupForm.state.$touched && signupForm.state.$invalid}">
                                <select placeholder="State" ng-model="formData.state" name="state" required="required" ng-options="state.abbr as state.name for state in CONST.STATES">
                                    <option value="">State</option>
                                </select>
                            </label>
                            <p ng-show="signupForm.state.$touched && signupForm.state.$error.required" class="form-error-detail">
                                <i class="fa fa-info-circle"></i> Select state.</p>
                        </div>
                    </div>
                </div>
            </div>

            <div class="form-group" style="clear:both">
                <h2>Where do you want us to send your money?</h2>
                <p class="subhead">All transactions such as sales, First Data equipment purchases and chargebacks will be credited or debited, as applicable, to the bank account specified below (the "Settlement Account")</p>
                <div class="column-6">
                    <div class="form-element" >
                        <label class="fancy-field"  fancy-field ng-class="{'error': (signupForm.ROUTING_NUMBER.$touched && signupForm.ROUTING_NUMBER.$invalid) || bankError}">
                            <input type="tel" placeholder="ABA routing number" ng-model="formData.ROUTING_NUMBER" ng-pattern="routingNumberPattern" name="ROUTING_NUMBER" required="required" maxlength="9" />
                        </label>
                        <p ng-show="signupForm.ROUTING_NUMBER.$touched && signupForm.ROUTING_NUMBER.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter your ABA routing number.</p>
                        <p ng-show="signupForm.ROUTING_NUMBER.$touched && signupForm.ROUTING_NUMBER.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Please enter a valid ABA number.</p>
                        <p ng-show="bankError" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> The routing number is not valid. If this is in error please continue.</p>
                        <p ng-show="bankErrorServerFails" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> We're sorry, but we are unable to get bank details at this time. You will be contacted in future to provide the routing number.</p>
                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.ACCOUNT_NUMBER.$touched && signupForm.ACCOUNT_NUMBER.$invalid}">
                            <input type="text" placeholder="Checking account number" ng-model="formData.ACCOUNT_NUMBER" ng-pattern="numberPattern" name="ACCOUNT_NUMBER" required="required" ng-minlength="1" maxlength="17" />
                        </label>
                        <p ng-show="signupForm.ACCOUNT_NUMBER.$touched && signupForm.ACCOUNT_NUMBER.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter your checking account number.</p>
                        <p ng-show="signupForm.ACCOUNT_NUMBER.$touched && signupForm.ACCOUNT_NUMBER.$error.pattern" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter valid account number.</p>

                    </div>
                    <div class="form-element" >
                        <label class="fancy-field" fancy-field ng-class="{'error': signupForm.ACCOUNT_NUMBER_confirm.$touched && signupForm.ACCOUNT_NUMBER_confirm.$invalid}">
                            <input type="text" placeholder="Re-enter checking account number" ng-model="ACCOUNT_NUMBER_confirm" ng-pattern="numberPattern" name="ACCOUNT_NUMBER_confirm" required="required" compare-to="formData.ACCOUNT_NUMBER" minlength="1" maxlength="17" />
                        </label>
                        <p ng-show="signupForm.ACCOUNT_NUMBER_confirm.$touched && signupForm.ACCOUNT_NUMBER_confirm.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Re-enter your checking account number.</p>
                        <p ng-show="signupForm.ACCOUNT_NUMBER_confirm.$touched && signupForm.ACCOUNT_NUMBER_confirm.$invalid && !signupForm.ACCOUNT_NUMBER_confirm.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Checking account number does not match.</p>
                        <p ng-show="signupForm.ACCOUNT_NUMBER_confirm.$touched && signupForm.ACCOUNT_NUMBER_confirm.$error.pattern && !signupForm.ACCOUNT_NUMBER_confirm.$error.required" class="form-error-detail">
                            <i class="fa fa-info-circle"></i> Enter valid account number.</p>

                    </div>

                </div>
                <div class="column-6">
                    <div class="form-element">
                        <img src="img/ach.png" />
                    </div>
                </div>
            </div>


            <div class="form-group form-actions column-12 align-center">
                <a class="btn submit disabled" ng-if="!signupForm.$valid || bankCheck" style="margin: 0 auto;">Continue</a>
                <a class="btn submit" ng-if="signupForm.$valid && !bankCheck" ng-class="{'disabled': clickedSubmit}" ng-disabled="clickedSubmit" style="margin: 0 auto;" ng-click="formSubmit(submitForm)"><i ng-show="clickedSubmit" class="fa fa-spinner fa-spin fa-lg fa-fw"></i>{{clickedSubmit ? ' Submitting...' : 'Continue'}}</a>
            </div>

        </div>
    </form>
</div>

Now that we’ve defined the HTML view above, let’s take a look at the JavaScript code that powers this view.

This code gathers all the relevant data from our form and then submits it to the POST Application/Update endpoint.

$scope.formSubmit = function(){
  if($scope.formData.name){
      $scope.formData.firstName = $scope.formData.name.split(" ")[0];
      $scope.formData.lastName = $scope.formData.name.split(" ")[1];
  }
  if($scope.formData.LEGAL_BUSINESS_NAME_SAME_AS_DBA != '0'){
      $scope.formData.legal_business_name = $scope.formData.DBA_NAME;
  }
  if($scope.formData.TAX_FILING_NAME_SAME_AS_BUSINESS_LEGAL_NAME != '0'){
      $scope.formData.tax_filing_name = $scope.formData.legal_business_name;
  }
  if($scope.formData.HOW_BUSINESS_FILES_TAXES != 'business_tax_id'){
      $scope.formData.EIN = $scope.formData.SocialSecurityNumber;
  }
  if($scope.formData.ORGANIZATION_TYPE == 'G' && $scope.formData.FOREIGN_OWNERSHIP == 'N'){
      $scope.formData.FOREIGN_OWNERSHIP = 'G';
  }
  if($scope.formData.ORGANIZATION_TYPE == 'T' && $scope.formData.FOREIGN_OWNERSHIP == 'N'){
      $scope.formData.FOREIGN_OWNERSHIP = 'D';
  }
  if($scope.formData.YEAR_BUSINESS_STARTED == $scope.thisYear && $scope.formData.MONTH_BUSINESS_STARTED > $scope.thisMonth) {
    $scope.signupForm.MONTH_BUSINESS_STARTED.$invalid = true;
    $scope.signupForm.$valid = false;
  }

  $scope.formData.dob = $scope.dob_year + '-' + $scope.dob_month + '-' + $scope.dob_day;
  var calculateAge = new Date($scope.dob_year,$scope.dob_month,$scope.dob_day );

  var ageDifMs = Date.now() - calculateAge.getTime();
  var ageDate = new Date(ageDifMs);
  var age =  Math.abs(ageDate.getUTCFullYear() - 1970);

  var a = parseInt($scope.formData.FACE_TO_FACE);
  var b = parseInt($scope.formData.PHONE_OR_EMAIL);
  var c = parseInt($scope.formData.INTERNET_PAY); // Considering Internet value in the Sum for Validation, Total must be 100%

  if(a+b+c != 100){
      $scope.signupForm.FACE_TO_FACE.$invalid = true;
      $scope.signupForm.$valid = false;
  }

  if(age<18){
       $scope.signupForm.dob_month.$invalid = true;
       $scope.signupForm.$valid = false;
  }

  if (!$scope.signupForm.$valid) {
    $scope.form_error = true;
    $scope.gotoAnchor('form-error');
    angular.forEach($scope.signupForm.$error, function (field) {
      angular.forEach(field, function(errorField){
          errorField.$setTouched();
      })
    });

    return;
  } else{
      $scope.form_error = false;
      $scope.clickedSubmit = true;
      $scope.tinError= false;
      $scope.submitSignupForm();
    }
};

Next Steps

In this section we discussed how to display, setup and initiate the merchant onboarding process. We defined a sample form and then the structure of that form by calling the POST Application/Update endpoint. In the next section, we’ll discuss the Merchant Agreement.

Next: Present the formal Merchant Agreement to the merchant.

Merchant Agreement

Overview

API: GET Contracts/Agreement

Check out the detailed API documentation of the GET Contracts/Agreement API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

The last step before submitting is to collect merchant information through the Merchant Agreement.

Partial example user interface displaying the Merchant Agreement Partial example user interface displaying the Merchant Agreement

Frontend example

Below is a view that displays the required information we need to collect.

This code gathers all the relevant data from our form and then submits it to the GET Contracts/Agreement endpoint.


<div class="main-content">
    <div class="container" id="terms">
        <table border="0" cellpadding="2" cellspacing="0">
            <thead>
            <tr>
                <th></th>
                <th style="vertical-align: middle; font-size: 14pt; text-align: center !important; line-height:24px;" colspan="3">MERCHANT PROCESSING APPLICATION AND AGREEMENT</th>
                <th align="right" style="vertical-align:middle;" class="print">(Page 1 of 3)</th>
                <th style="background: white !important;"><img ng-if="isLogoVisible" ng-src="{{encodedLogoSrc}}" style="max-width: 100%; max-height:30px;"/></th>
            </tr>
            <tr>
              <td style="min-height:10px; height:10px;"></td>
            </tr>
            <tr>
                <th style="text-align: left !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.pgVersion}}</th>
                <th style="text-align: center !important; border: 1px solid black;" colspan="3">COMPLETE SECTIONS (1-9)</th>
                <th  style="text-align: right !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.version}}</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td class="width-5" colspan="3">
                    Merchant #: <span class="dottedLine">N/A</span></td>
                <td class="align-right width-5" colspan="2">
                    Loc.<span class="dottedLine align-center ">1</span> of <span class="dottedLine align-center ">1</span>
                </td>
            </tr>
            </tbody>
        </table>
        <hr>
        <!-- (1) TELL US ABOUT YOUR BUSINESS -->
        <table border="0" cellpadding="0" cellspacing="0">
            <tr>
                <th>(1) TELL US ABOUT YOUR BUSINESS</th>
            </tr>
        </table>
        <div class="section">
            <table class="border-bottom" cellpadding="2" cellspacing="0">
                <tbody>
                <tr>
                    <td class="width-8" colspan="5">
                        <label>Legal Name:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.legalDbaName}}</span>
                    </td>
                    <td class="width-2" colspan="1">
                        <label>Store #:</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <tr>
                    <td class="width-1" colspan="3">
                        <label>DBA/Outlet Name:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.dbaName}}</span>
                    </td>
                    <td colspan="3">
                        <label>First/Last Contact Name:</label>
                        <span class="user-input">{{merchantBean.firstName}} {{merchantBean.lastName}}</span>
                    </td>
                </tr>
                <tr>
                    <td class="width-2" colspan="2">
                        <label>Address:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessAddress}}</span>
                    </td>
                    <td colspan="1">
                        <label>Suite #:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessAptSuite || 'N/A'}}</span>
                    </td>
                    <td colspan="1">
                        <label>City:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessCity}}</span>
                    </td>
                    <td colspan="1">
                        <label>State:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessState}}</span>
                    </td>
                    <td colspan="1">
                        <label>Zip:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessZipcode}}</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>Business Phone:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessPhoneNumber}}</span>
                    </td>
                    <td colspan="3">
                        <label>Customer Service Phone:</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>Fax Phone:</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td colspan="3">
                        <label>Cell Phone:</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>E-mail Address:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.emailAddress}}</span>
                    </td>
                    <td colspan="3">
                        <label>Website URL Address:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.url || 'N/A'}}</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>TIN Type:</label>
                        {{!isTinTypeSsn ?'&#9746':'☐'}} EIN (Fed Tax ID #)&nbsp;&nbsp;
                        {{isTinTypeSsn ?'&#9746':'☐'}} SSN
                    </td>
                    <td colspan="3">
                        <label>Retrieval Requests:</label>
                        &#9744; Dedicated 24 hour fax&nbsp;&nbsp;
                        &#9744; No fax; mail&nbsp;&nbsp;
                        ☒ Dispute Manager
                    </td>
                </tr>
                </tbody>
            </table>
            <br/>
            <table class="border" style="background: #eee;">
                <tr>
                    <td colspan="3"><strong>NOTE:</strong> Failure to provide accurate information may require us to withhold income tax from your funding per IRS regulations.</td>
                </tr>
                <tr>
                    <td align="center">
                        <label>Name <span style="font-style: italic">(as it appears on your income tax return)</span></label><br>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.taxBusinessName}}</span>
                    </td>
                    <td align="center">
                        <label>&#9744; Federal Tax ID# <span style="font-style: italic">(as it appears on your income tax return)</span></label><br>
                        <span class="user-input">{{maskDigit((merchantBean.merchantBusinessBean.socialSecurityNumber != merchantBean.merchantBusinessBean.employerIdNumberTax) ? merchantBean.merchantBusinessBean.employerIdNumberTax : merchantBean.merchantBusinessBean.socialSecurityNumber )}}</span>
                    </td>
                    <td align="center">
                        <label>{{merchantBean.merchantBusinessBean.isCertified ?'&#9746':'☐'}} I certify that I am a foreign entity/nonresident alien.</label><br>
                      <span style="font-style: italic">(If checked, please attach IRS Form W-8.)</span>
                    </td>
                </tr>
            </table>
            <br/>
            <table class="border-bottom">
                <tbody>
                <tr>
                    <td colspan="2">
                        <label>Product/Services you sell:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.mccDescription}}</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <label>Time frame from transaction to delivery:</label>
                        <strong>% of orders delivered in:</strong>
                        0-7 days <span class="user-input dottedLine">100</span>% <strong>+</strong>
                        8-14 days <span class="user-input dottedLine">0</span>% <strong>+</strong>
                        15-30 days <span class="user-input dottedLine">0</span>% <strong>+</strong>
                        over 30 days <span class="user-input dottedLine">0</span>% <strong>= 100%</strong>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <label>Who performs product/service fulfillment?</label>
                        Direct <span class="user-input dottedLine">Yes</span>
                        Vendor <span class="user-input dottedLine"></span> If Vendor, add name, address, phone.
                        &#9744; Other: <em>(specify)</em> <span class="user-input"></span>
                    </td>
                </tr>
                <tr>
                    <td>
                        <label>Do you use any third party to store, process or transmit cardholder data? </label>
                        &#9744; Yes&nbsp;&nbsp;
                        ☒ No&nbsp;&nbsp;
                    </td>
                    <td>
                        <label>If yes, give name/address:</label>
                        <span class="user-input"></span>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <label>Please identify any Software used for storing, transmitting, or processing card transactions or authorization requests.</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
        <hr>
        <!-- ( 2 ) OWNERSHIP -->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th>(2) OWNERSHIP</th>
            </tr>
        </table>
        <div class="section">
            <table class="border-bottom" cellpadding="2" cellspacing="0">
                <tr>
                    <td colspan="1">
                        <label>State Organized:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.stateIncorp}}</span>
                    </td>
                    <td colspan="1">
                        <label>Mo/Yr Started:</label>
                        <span class="user-input">{{merchantBean.businessYearStarted}}</span>
                    </td>
                    <td colspan="4">
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="I" ? "&#9746;" : "☐" }}
                  </span> Sole Ownership
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="P" ? "&#9746;" : "☐" }}
                  </span> Partnership
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="T" ? "&#9746;" : "☐" }}
                  </span> Non Profit/Tax Exempt
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="C" ? "&#9746;" : "☐" }}
                  </span> Public Corp.
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="PRC" ? "&#9746;" : "☐" }}
                  </span> Private Corp.
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="L" ? "&#9746;" : "☐" }}
                  </span>  L.L.C
                  <span class="user-input">
                    {{merchantBean.organizationTypeReferenceCode ==="G" ? "&#9746;" : "☐" }}
                  </span> Govt.
                    </td>
                </tr>
                <td colspan="3">
                    <label>Owner/Partner/Officer Name:</label>

                    <span class="user-input">{{merchantBean.firstName}}</span> &nbsp;<span class="user-input">{{merchantBean.lastName}}</span>
                </td>
                <td colspan="2">
                    <label>D.O.B.:</label>
                    <span class="user-input">{{merchantBean.dateOfBirth}}</span>
                </td>
                <td>
                    <label>Social Security #:</label>
                    <span class="user-input">{{maskDigit(merchantBean.merchantBusinessBean.socialSecurityNumber)}}</span>
                </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>Home Phone</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.phoneNumber}}</span>
                    </td>
                    <td colspan="3">
                        <label>Ownership %:</label>
                        <span class="user-input">100</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <label>Home Address:</label>
                        <span class="user-input">{{merchantBean.homeAddress}}  {{merchantBean.homeAddress2 || ''}} </span>
                    </td>
                    <td>
                        <label>City:</label>
                        <span class="user-input">{{merchantBean.city}}</span>
                    </td>
                    <td>
                        <label>State</label>
                        <span class="user-input">{{merchantBean.state}}</span>
                    </td>
                    <td>
                        <label>Zip:</label>
                        <span class="user-input">{{merchantBean.zipCode}}</span>
                    </td>
                    <td>
                        <label>Country</label>
                        <span class="user-input">{{merchantBean.country}}</span>
                    </td>
                </tr>


                <!-- Need To discuss !-->
                </tr>
                <td colspan="3">
                    <label>Owner/Partner/Officer Name:</label>
                    <span class="user-input">N/A</span>
                </td>
                <td colspan="2">
                    <label>D.O.B.:</label>
                    <span class="user-input">N/A</span>
                </td>
                <td>
                    <label>Social Security #:</label>
                    <span class="user-input">N/A</span>
                </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label>Home Phone</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td colspan="3">
                        <label>Ownership %:</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <label>Home Address:</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td>
                        <label>City:</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td>
                        <label>State</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td>
                        <label>Zip:</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td>
                        <label>Country</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <!-- Need To discuss !-->
            </table>
        </div>
        <hr>
        <!-- Need to discuss -->
        <!-- ( 3 ) BUSINESS FINANCIAL DATA -->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th>(3) BUSINESS FINANCIAL DATA</th>
            </tr>
        </table>
        <div class="section">
            <table cellpadding="2" cellspacing="0">
                <tr>
                    <td colspan="3" style="border-right: 1px solid #aaa;">
                        <table>
                            <tr>
                                <td colspan="2">
                                    <table>
                                        <tr>
                                            <td><strong>Total Annual Volume</strong></td>
                                            <td class="align-right"><strong>This Location</strong></td>
                                            <td class="align-right"><strong>All Locations</strong></td>
                                        </tr>
                                        <tr>
                                            <td>MasterCard/ Visa</td>
                                            <td class="align-right">$<span class="user-input dottedLine">{{annualMcVisaFormatted || 'N/A'}}</span></td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                        </tr>
                                        <tr>
                                            <td>Discover/PayPal</td>
                                            <td class="align-right">$<span class="user-input dottedLine">{{discoverEnabled ? annualDiscFormatted : 'N/A'}}</span></td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                        </tr>
                                        <tr>
                                            <td>American Express OptBlue®</td>
                                            <td class="align-right">$<span class="user-input dottedLine">{{(amexEnabled && isAmexOptBlue) ? annualAmexFormatted : 'N/A'}}</span></td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                        </tr>
                                        <tr>
                                            <td>Voyager</td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                        </tr>
                                        <tr>
                                            <td>WEX</td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                            <td class="align-right">$<span class="user-input dottedLine">N/A</span></td>
                                        </tr>
                                    </table>
                                </td>
                                <td>
                                    <table>
                                        <tr>
                                            <td colspan="2">&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>Average Card Sale Amount</td>
                                            <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.avgTicket}}</span></td>
                                        </tr>
                                        <tr>
                                            <td>Highest Sale Amount</td>
                                            <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.merchantBusinessBean.hiTicket}}</span></td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td style="border-right: 1px solid #aaa;">
                        <table>
                            <tr>
                                <td>
                                    <table>
                                        <tr>
                                            <td>Card Present</td>
                                            <td class="align-right"><span class="user-input dottedLine">{{merchantBean.merchantBusinessBean.f2fPercent}}</span>%</td>
                                        </tr>
                                        <tr>
                                            <td>Internet</td>
                                            <td class="align-right"><span class="user-input dottedLine">{{ merchantBean.merchantBusinessBean.internetPercent}}</span>%</td>
                                        </tr>
                                        <tr>
                                            <td>Mail Order / Direct Marketing</td>
                                            <td class="align-right"><span class="user-input dottedLine">N/A</span>%</td>
                                        </tr>
                                        <tr>
                                            <td>Phone Order</td>
                                            <td class="align-right"><span class="user-input dottedLine">{{merchantBean.merchantBusinessBean.motoPercent}}</span>%</td>
                                        </tr>
                                        <tr>
                                            <td><strong>Total</strong></td>
                                            <td class="align-right"><span class="user-input">100% </span></td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td>
                        <table>
                            <tr>
                                <td>
                                    <table>
                                        <tr>
                                            <td>Swiped</td>
                                            <td class="align-right"><span class="user-input dottedLine">{{merchantBean.merchantBusinessBean.f2fPercent}}</span>%</td>
                                        </tr>
                                        <tr>
                                            <td>Keyed</td>
                                            <td class="align-right"><span class="user-input dottedLine">{{ merchantBean.merchantBusinessBean.internetPercent + merchantBean.merchantBusinessBean.motoPercent}}</span>%</td>
                                        </tr>
                                        <tr>
                                            <td><strong>Total</strong></td>
                                            <td class="align-right"><span class="user-input">100%</span></td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </div>
        <hr>
        <!-- ( 4 ) BANKING AND FUNDING INFORMATION -->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th>(4) BANKING AND FUNDING INFORMATION</th>
            </tr>
        </table>
        <div class="section">
            <table class="border-bottom" cellpadding="2" cellspacing="0">
                <tr>
                    <td>
                        <label>ABA #:</label>
                        <span class="user-input">{{merchantBean.abaNumber}}</span>
                    </td>
                    <td>
                        <label>DDA #:</label>
                        <span class="user-input">{{merchantBean.accountNumber}}</span>
                    </td>
                </tr>
                <!-- TODO: Need to discuss -->
                <tr>
                    <td>
                        <label>ABA #:</label>
                        <span class="user-input">N/A</span>
                    </td>
                    <td>
                        <label>DDA #:</label>
                        <span class="user-input">N/A</span>
                    </td>
                </tr>
                <!-- TODO: Need to discuss -->
                <tr>
                    <td>
                        <label>Deduct Fees:</label>
                        ☒ Daily <span style="font-style: italic">(excluding Flat Rate)</span>&nbsp;&nbsp;
                        &#9744; Monthly <span style="font-style: italic">(fee will apply)</span>
                    </td>
                    <td>
                        <label>Bank Will Fund:</label>
                        ☒ Outlet&nbsp;&nbsp;
                        &#9744; Head Office</span>
                    </td>
                </tr>
            </table>
        </div>
        <hr>
        <!-- ( 5 ) ENTITLEMENTS-->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th>(5) ENTITLEMENTS</th>
            </tr>
        </table>
        <div class="section">
            <table class="border-bottom" cellpadding="2" cellspacing="0">
                <tr>
                    <td colspan="2">
                        <span class="user-input"> {{(amexEnabled && isAmexOptBlue) ?'☒':'☐'}}</span> American Express OptBlue&reg;
                    </td>
                    <td>
                        <span class="user-input"> {{debitEnabled ?'☒':'☐'}}</span> Pin Debit
                    </td>
                    <td>
                        <span class="user-input">&#9744;</span> EBT  SNAP/FNS#:
                        <span class="user-input dottedLine"></span>
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <span class="user-input">&#9744;</span> Voyager Fleet&nbsp;&nbsp;&nbsp;
                        <span style="font-style: italic !important;">(Participation in Voyager Tax Exempt Program):</span> <span class="user-input">&#9744;</span> Yes <span class="user-input">&#9744;</span> No
                        <span style="font-style: italic !important;">(if yes, additional request form required)</span>
                    </td>
                    <td colspan="2">
                        <span class="user-input">&#9744;</span> WEX Full Acquiring
                        <span class="user-input">&#9744;</span> WEX (Non-Full Svc)
                        <span class="user-input">&#9744;</span> MC Fleet
                    </td>
                </tr>
                <tr>
                    <td colspan="3">
                        <span class="user-input">{{(amexEnabled && !isAmexOptBlue) ?'☒':'☐'}}</span> American Express Pass Through SE (existing): <span class="user-input dottedLine"></span>
                    </td>
                    <td colspan="2">
                        Pass Through:
                        <span class="user-input">&#9744;</span> Split Dial
                        <span class="user-input">&#9744;</span> EDC
                    </td>
                </tr>
            </table>
        </div>
        <hr>
        <hr class="page-break">
        <table>
            <tr>
                <th class="print"></th>
                <th colspan="3" class="print" style="vertical-align: middle; font-size: 16pt; text-align: center !important;" colspan="3">MERCHANT PROCESSING APPLICATION AND AGREEMENT</th>
                <th class="print" align="right">(Page 2 of 3)</th>
            </tr>
            <tr>
                <td></td>
            </tr>
            <tr>
                <td class="width-5 print" colspan="3">
                    DBA Name: <span class="user-input">{{merchantBean.merchantBusinessBean.dbaName}}</span></td>
                <td class="align-right width-5 print" colspan="2">
                    Loc.<span class="dottedLine align-center ">1</span> of <span class="dottedLine align-center ">1</span>
                </td>
            </tr>
        </table>

        <!-- ( 6 ) EQUIPMENT DETAILS -->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th class="print" style="text-align: left !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.pgVersion}}</th>
                <th colspan="3">(6) EQUIPMENT DETAILS</th>
                <th class="print" style="text-align: right !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.version}}</th>
            </tr>
        </table>
        <div class="section">
            <table class="border" cellpadding="2" cellspacing="0">
                <tr class="align-center">
                    <td>
                      Rental &#149; Purchase <br>
                      Customer-Owned <br>
                      <span style="vertical-align: super;font-size: smaller;">*</span>Lease</span>
                    </td>
                    <td>QTY</td>
                    <td>IP</td>
                    <td>Equipment Type <br> (i.e., Clover/Terminal/VAR)</td>
                    <td>Industry Type</td>
                    <td>Model Code and Name</td>
                    <td>Unit Price w/o Tax and S&H</td>
                    <td>Customer-Owned Equipment Track/Version/Serial #</td>
                </tr>
                <tr class="align-center" ng-repeat="val in merchantBean.equipment">
                    <td><span class="user-input">{{val.fullNameTerm}}</span></td>
                    <td><span class="user-input">{{val.quantity}}</span></td>
                    <td><span class="user-input">&#9744;</span></td>
                    <td><span class="user-input">{{val.equipmentType}}</span></td>
                    <td><span class="user-input">{{merchantBean.merchantBusinessBean.businessType}}</span></td>
                    <td><span class="user-input">{{val.modelName}}</span></td>
                    <td align="left" class="align-left">$ <span class="user-input">{{(val.unitPrice | currency : "")}}</span></td>
                    <td><span class="user-input">N/A</span></td>
                </tr>
            </table>
            <table>
                <tr>
                    <td>
                        <strong>Shipping and Handling:</strong>&nbsp;&nbsp;
                        Standard $<span class="user-input dottedLine">19.99</span>&nbsp;&nbsp;
                        Overnight $<span class="user-input dottedLine"></span>
                    </td>
                    <td><span class="user-input">{{emvEnabled ?'&#9746':'☐'}}</span> Enable EMV</td>
                </tr>
            </table>
            <p>*See Equipment Lease Agreement for the Terms and Conditions governing your Leased equipment.</p>
        </div>

        <!-- ( 7 ) FEE SCHEDULE -->
        <table class="border" cellpadding="2" cellspacing="0">
            <tr>
                <th>(7) FEE SCHEDULE</th>
            </tr>
        </table>
        <div class="section">
            <table border="0" cellpadding="0" cellspacing="0">
                <tr>
                    <td>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="2" style="text-align: center !important;" class="small">Product Subscriptions (Monthly)</td>
                            </tr>
                            <tr>
                                <td>Clover Services (Per Station)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.cloverServiceFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Insightics Solution</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.insighticsFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Perka Solution</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td>TransArmor Solution</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.transarmorSolution || 'N/A'}}</span></td>
                            </tr>
                        </table>
                        <br>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="2" style="text-align: center !important;" class="small">Compliance Fees</td>
                            </tr>
                            <tr>
                                <td>Monthly Compliance Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.monthlySVCFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Annual Compliance Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.annualComplianceFee || 'N/A'}}</span></td>
                            </tr>
                        </table>
                        <br>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="2" style="text-align: center !important;" class="small">Mobile Payments Solution (Clover Go)</td>
                            </tr>
                            <tr>
                                <td>Mobile Payments Setup Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.fdMobilePaySetupFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Mobile Payments Setup Fee (Per Terminal ID)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.mobilePaySVCFee || 'N/A'}}</span></td>
                            </tr>
                        </table>
                        <br>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="2" style="text-align: center !important;" class="small">eCommerce/Wireless Solutions</td>
                            </tr>
                            <tr>
                                <td>Payeezy Setup Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.payeezySetupFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Payeezy Monthly Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.e4monthlyFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Payeezy Webstore Solution</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.payeezyWebstoreFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Global ePricing MC/Visa Service Fee</td>
                                <td class="align-right"><span class="user-input dottedLine">{{merchantBean.eComEpricing || 'N/A'}}</span> %</td>
                            </tr>
                            <tr>
                                <td>Internet Set-Up Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.globalGatewaySetupFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Internet Authorization Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.internetAuthFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Internet Service Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td>Wireless Access Fee (Per User)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.wirelessAccessFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Other: <span class="user-input dottedLine"></span></td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                        </table>
                        <br>
                        <!-- TODO: neeed Discuss -->
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="4" style="text-align: center !important;" class="small">Petroleum Services</td>
                            </tr>
                            <tr>
                                <td colspan="2">Datawire Micronode
                                    <span class="user-input">&#9744;</span> Yes
                                    <span class="user-input">&#9744;</span> No
                                </td>
                                <td>Datawire Monthly Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Voyager</td>
                                <td>Authorization Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Sales/Credit Discount</td>
                                <td class="align-right"><span class="user-input dottedLine">N/A</span> %</td>
                            </tr>
                            <tr>
                                <td colspan="2">WEX</td>
                                <td>Full Service Authorization Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Sales/Credit Discount</td>
                                <td class="align-right"><span class="user-input dottedLine">N/A</span> %</td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Chargeback Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Retrieval Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Non-Full Service Authorization Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                        </table>
                        <!-- TODO: neeed Discuss -->
                    </td>
                    <td>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="2" style="text-align: center !important;" class="small">Start-Up Fees</td>
                            </tr>
                            <tr>
                                <td>Application Fee (Non-Refundable)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.applicationFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Reprogramming Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.programmingFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Debit Set-Up Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.debitStartUp || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Miscellaneous Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td><span style="vertical-align: super;font-size: smaller;">*</span>Equipment Purchase</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{(equipmentPurchase | currency : "") || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td>Other: <span class="user-input dottedLine"></span></td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                            <tr>
                                <td>Total Amount:</td>
                                <td class="align-right">$ <span class="user-input dottedLine">{{(totalAmountStartUpFees | currency : "") || 'N/A'}}</span> w/o tax</td>
                            </tr>
                        </table>
                        <table style="border:1px solid; border-top:0;">
                            <tr>
                                <td><span style="vertical-align: super;font-size: smaller;">*</span>Plus applicable State/City/Local sales tax.</td>
                            </tr>
                        </table>
                        <br>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="4" class="small">Debit Fees</td>
                            </tr>
                            <tr>
                                <td colspan="2">Bundled Debit <br>(Applies to MC/V/Disc Non-PIN and PIN Debit)</td>
                                <td>Discount Rate</td>
                                <td class="align-right"><span class="user-input dottedLine">{{merchantBean.bundledDebitRate || 'N/A'}}</span> %&nbsp;</td>
                            </tr>
                            <tr>
                                <td colspan="2"></td>
                                <td>Sales/Return Trans Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.bundledDebitFee || 'N/A'}}</span><span style="vertical-align: super;font-size: smaller;">&nbsp;&nbsp;</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Unbundled Debit <br>(Applies to PIN Debit only)</td>
                                <td>Transaction Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.unbundledDebitFee || 'N/A'}}</span><span style="vertical-align: super;font-size: smaller;">*</span></td>
                            </tr>
                        </table>
                        <table style="border:1px solid; border-top:0;">
                            <tr>
                                <td><span style="vertical-align: super;font-size: smaller;">*</span>Plus applicable PIN Debit Network fees.</td>
                            </tr>
                        </table>
                        <br>
                        <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                            <tr>
                                <th colspan="3" class="small">Miscellaneous Fees* (If Applicable)</td>
                            </tr>
                            <tr>
                                <td colspan="2">TransArmor Data Protection Service (Tokenization & Encryption)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.transarmorDataProtection || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Non-Receipt of PCI Validation</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.pciValidation || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Business Advantage Pkg</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.busAdvPkg || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Minimum Processing Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.minimumProcessingFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Paper Statement Fee (Default is free electronic statement)</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.paperStatementFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Chargeback Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.chargebackFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">ACH Reject Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.achRejectFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Batch Settlement Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.batchSettlementFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Monthly Funding Advantage</td>
                                <td class="align-right"><span class="user-input dottedLine">{{merchantBean.monFundAdv || 'N/A'}}</span> %</td>
                            </tr>
                            <tr>
                                <td colspan="2">AVS</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.avsFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Voice Authorization</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.voiceAuthFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">MC/V/Discover Network Access Fee</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.mcNetworkAccessFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">MC License Volume Fee</td>
                                <td class="align-right"><span class="user-input dottedLine">{{merchantBean.mcLicenseFee || 'N/A'}}</span> %</td>
                            </tr>
                            <tr>
                                <td colspan="2">MC Cross Border Fee USD</td>
                                <td class="align-right"><span class="user-input dottedLine">{{merchantBean.mcCrossBorderFee || 'N/A'}}</span> %</td>
                            </tr>
                            <tr>
                                <td>Visa Int’l Service Fee</td>
                                <td class="align-right">USD: <span class="user-input dottedLine">{{merchantBean.visaIntlUSD || 'N/A'}}</span> %</td>
                                <td class="align-right">Non-USD: <span class="user-input dottedLine">{{merchantBean.visaIntlNonUSD || 'N/A'}}</span> %</td>
                            </tr>
                            <tr>
                                <td colspan="2">American Express Pass Through</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.amexPassThru || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">EBT</td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">{{merchantBean.ebtFee || 'N/A'}}</span></td>
                            </tr>
                            <tr>
                                <td colspan="2">Other: <span class="user-input dottedLine"></span></td>
                                <td class="align-right">$ <span class="user-input dottedLine space-right">N/A</span></td>
                            </tr>
                        </table>
                        <table style="border:1px solid; border-top:0;">
                            <tr>
                                <td><span style="vertical-align: super;font-size: smaller;">*</span>You may be charged, if applicable, additional Card/Payments Organization pass through fees and costs for your transactions as described in the Interchange Qualification Matrix and American Express OptBlue® Guide available at www.businesstrack.com.</td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
            <br>
            <hr class="page-break">
            <table>
                <tr>
                    <th class="print"></th>
                    <th colspan="3" class="print" style="vertical-align: middle; font-size: 16pt; text-align: center !important;" colspan="3">MERCHANT PROCESSING APPLICATION AND AGREEMENT</th>
                    <th class="print" align="right">(Page 3 of 3)</th>
                </tr>
                <tr>
                    <td></td>
                </tr>
                <tr>
                    <td class="width-5 print" colspan="3">
                        DBA Name: <span class="user-input">{{merchantBean.merchantBusinessBean.dbaName}}</span></td>
                    <td class="align-right width-5 print" colspan="2">
                        Loc.<span class="dottedLine align-center ">1</span> of <span class="dottedLine align-center ">1</span>
                    </td>
                </tr>
            </table>
            <table class="border" cellpadding="2" cellspacing="0">
                <tr>
                    <th>(7) FEE SCHEDULE (cont'd)</th>
                </tr>
            </table>
            <table cellpadding="2" cellspacing="0" class="border">
                <tr>
                    <td colspan="2">Pricing Method<span style="vertical-align: super;font-size: smaller;">A</span></td>
                    <td align="center">MC/Visa/Discover Ntwk/PayPal 2-Tier</td>
                    <td align="center">MC/Visa/Discover Ntwk/PayPal 3-Tier</td>
                    <td colspan="2" align="center">Transaction Fees<br> (Applies to MC/Visa/Discover Ntwk/PayPal 2-Tier and<br> MC/Visa/Discover Ntwk/PayPal 3-Tier ONLY)</td>
                    <td align="center">MC / Visa /Discover Ntwk / PayPal / American Express OptBlue® Discount Rate</td>
                    <td align="center">IC Plus</td>
                </tr>
                <tr>
                    <td colspan="8" align="center" style="background:#eee;">Qualified Discount Rates</td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk/PayPal Credit Discount Rate</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditRateTier2 || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditRateTier3 || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/V/Discover Ntwk/PayPal Credit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaCreditFeeTier || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditRateRateAuth || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditRateInterchange || 'N/A'}}</span> %</td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk/PINless POS <span style="vertical-align: super;font-size: smaller;">*</span>Non-PIN (Signature) Debit Discount Rate</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitRateTier2 || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitRateTier3 || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/V/Discover Ntwk/PINless POS Non-PIN (Signature) Debit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaDebitFeeTier || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitRateRateAuth || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitRateInterchange || 'N/A'}}</span> %</td>
                </tr>
                <tr>
                    <td colspan="2">American Express OptBlue®</td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td colspan="2" style="background: #aaa;">
                        <table>
                            <tr>
                                <td colspan="2"></td>
                                <td class="align-right"></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.amexDiscountRate || 'N/A'}}</span> %</td>
                </tr>
                <tr>
                    <td colspan="8" align="center" style="background:#eee;">Mid-Qualified Discount Rates (Does not apply to MC / Visa / Discover/PayPal 2 Tier)</td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk/PayPal Credit Discount Rate</td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCardMQRate || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/V/Discover Ntwk/PayPal Credit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaCardMQFee || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk <span style="vertical-align: super;font-size: smaller;">*</span>Non-PIN (Signature) Debit Discount Rate</td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCardNPMQRate || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/V/Discover Ntwk Non-PIN (Signature) Debit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaCardNPMQFee || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                </tr>
                <tr>
                    <td colspan="8" align="center" style="background:#eee;">Non-Qualified Discount Rates</td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk/PayPal Credit Discount Rate</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditNonQualRateTier2 || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaCreditNonQualRateTier3 || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/V/Discover Ntwk/PayPal Credit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaCreditNonQualFeeTier || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                </tr>
                <tr>
                    <td colspan="2">MC/Visa/Discover Ntwk <span style="vertical-align: super;font-size: smaller;">*</span>Non-PIN (Signature) Debit Discount Rate</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitNonQualRateTier2 || 'N/A'}}</span> %</td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.visaDebitNonQualRateTier3 || 'N/A'}}</span> %</td>
                    <td colspan="2">
                        <table>
                            <tr>
                                <td colspan="2">MC/Visa/Discover Ntwk Non-PIN (Signature) Debit Trans Fee</td>
                                <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaDebitNonQualFeeTier || 'N/A'}}</span></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                </tr>
                <tr>
                    <td colspan="8" style="background:#eee;"><span style="vertical-align: super;font-size: smaller;">*</span>Fees do not apply if Bundled Debit is chosen</td>
                </tr>
                <tr>
                    <td colspan="2">MC/V/ Discover Ntwk/PINless POS Authorization & Return Transaction Fee</td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td colspan="2" style="background: #aaa;">
                        <table>
                            <tr>
                                <td colspan="2"></td>
                                <td class="align-right"></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.visaCreditFeeRateAuth || 'N/A'}}</span></td>
                    <td class="align-right">$ <span class="user-input dottedLine">{{merchantBean.visaCreditFeeInterchange || 'N/A'}}</span></td>
                </tr>
                <tr>
                    <td colspan="2">

                        Non-Qual Surcharge Fee<br>
                        (excluding Card/Payments Organization pass-through fees, and any interchange rate difference)<br>
                        <hr>
                        Applies to Non-Qualified MC, Visa, Discover Ntwk/ PayPal, and/or Non-PIN (Signature) Debit Transactions. <br>Rewards Cards Surcharge Rate
                    </td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td class="align-right" style="background: #aaa;"></td>
                    <td colspan="2" style="background: #aaa;">
                        <table>
                            <tr>
                                <td colspan="2"></td>
                                <td class="align-right"></td>
                            </tr>
                        </table>
                    </td>
                    <td class="align-right"><span class="user-input dottedLine">{{merchantBean.nonQualifiedSurchargeFee || 'N/A'}}</span>% <br><br><br><br><br><span class="user-input dottedLine">{{merchantBean.rewardsSurchargeRate || 'N/A'}}</span> % </td>
                    <td class="align-right" style="background: #aaa;"></td>
                </tr>
            </table>
            <p><span style="vertical-align: super;font-size: smaller;">A</span> Interchange Rates are variable and are determined by how your transactions clear. Please see your Interchange Rate Schedule, Interchange Qualification Matrix and American Express OptBlue® Guide for Interchange Rates & Dues/Assessments and qualification criteria as of the date of this Application. The Interchange Rates and Dues/Assessments are subject to change. American Express OptBlue® has Program Pricing which is not Interchange and which is subject to change.</p>
            <br>
            <table cellpadding="2" cellspacing="0" class="border">
                <tr>
                    <td colspan="2" align="center">Swiped/Non-Swiped<br>(if selected, the discount rates below apply to all card types and brands accepted)</td>
                </tr>
                <tr>
                    <td>
                        <table>
                            <tr>
                                <td>Swiped or Dipped Transactions</td>
                                <td>
                                    <table>
                                        <tr>
                                            <td></td>
                                            <td colspan="5"><span class="user-input dottedLine space-left">{{merchantBean.swipedRate || 'N/A'}}</span> % of gross transaction</td>
                                        </tr>
                                        <tr>
                                            <td>+</td>
                                            <td colspan="5">$ <span class="user-input dottedLine">{{merchantBean.swipedFee || 'N/A'}}</span> per transaction </td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td>
                        <table>
                            <tr>
                                <td>Non-Swiped and Non-Dipped Transactions</td>
                                <td>
                                    <table>
                                        <tr>
                                            <td></td>
                                            <td colspan="5"><span class="user-input dottedLine space-left">{{merchantBean.nonSwipedRate || 'N/A'}}</span> % of gross transaction</td>
                                        </tr>
                                        <tr>
                                            <td>+</td>
                                            <td colspan="5">$ <span class="user-input dottedLine">{{merchantBean.nonSwipedFee || 'N/A'}}</span> per transaction </td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </div>

        <!--  ( 8 ) AGREEMENT APPROVAL -->
        <table border="0" cellpadding="5" cellspacing="0">
            <tr>
                <th>(8) AGREEMENT APPROVAL</th>
            </tr>
            <tbody style="text-align:justify;">
            <tr>
                <td><strong>On behalf of myself as an individual, and the entity on whose behalf I am signing, (A) I authorize [Servicers], the applicable Card / Payments Organizations, and its and their Affiliates, third party subcontractors and/or agents:</strong> (i) to use, disclose, and exchange amongst them, the information in the Agreement and information about me personally, (including by requesting, personal and business consumer reports, bank references, and other information as necessary from time to time), for marketing and administrative purposes, verification purposes, purposes under the Merchant Processing Application and Agreement (“MPA”), if approved, and any other uses permitted by law; (ii) to inform me directly about the contents of requested consumer reports (including the name and address of the agency furnishing the report), and (ii) to receive any and all personal and business credit financial information from all references, including banks and consumer reporting agencies, which are hereby released to provide that information; and (B) I certify that: (i) The federal taxpayer identification number and corresponding filing name provided herein are correct; (ii) The statements made and agreed to in this MPA, to which I have not made any alterations or stricken out any language, are true, complete and accurate, and may be relied upon as current unless changed or updated per the Notice provisions of Agreement; (iii) I can read and understand the English language; (iv) I have received and read a copy of the (a) MPA (consisting of Sections 1-9), (b) General Terms and Conditions, (c) Confirmation Page (version [{{merchantBean.pgVersion}}]), and (d) Interchange rate Schedule. I understand that the Interchange Qualification Matrix and American Express OptBlue® Guide and Your Payments Acceptance Guide are available at www.businesstrack.com and the signature below is for the entire contents of the listed documents; v) I have authority to bind the entity on whose behalf I am signing below; I further acknowledge and agree that I will not use my merchant account and/or the Services for illegal transactions, for example, those prohibited by the Unlawful Internet Gambling Enforcement Act, 31 U.S.C. Section 5361 et seq, as may be amended from time to time or for processing and acceptance of transactions in certain jurisdictions pursuant to 31 CFr Part 500 et seq. and other laws enforced by the Office of Foreign Assets Control (OFAC).</td>
            </tr>
            </tbody>
        </table>
        <table border="0" cellpadding="2" cellspacing="0">
            <tr>
                <td>
                    <span class="bold">Merchant Business Principal:</span>
                    <div class="signature-box">
                        <canvas id="signature1" ng-mousemove="canMouseUp(1)" my-touchend="canMouseUp(1)" sketch></canvas>
                        <span ng-show="signature1Empty">Please sign in the box with mouse or finger.</span>
                        <a class="button" ng-hide="signature1Empty" ng-click="resetCanvas(1)">Clear Signature</a>
                    </div>
                    <p>Date: <span class="user-input dottedLine">{{signature1Date | date:'shortDate'}}</span></p>
                    <p>Print Name: <span class="user-input dottedLine">{{merchantBean.firstName}} {{merchantBean.lastName}}</span></p>
                    <div>
                        <span class="user-input">{{merchantBean.title ==="PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> President
                        <span class="user-input">{{merchantBean.title ==="VICE PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> Vice President
                        <span class="user-input">{{merchantBean.title ==="MEMBER LLC" ? "&#9746;" : "&#9744;" }}</span> Member L.L.C
                        <span class="user-input">{{merchantBean.title ==="OWNER" ? "&#9746;" : "&#9744;" }}</span> Owner
                        <span class="user-input">{{merchantBean.title ==="PARTNER" ? "&#9746;" : "&#9744;" }}</span> Partner
                        <span class="user-input">{{isTitleOther ? "&#9746;" : "&#9744;" }}</span> Other <span class="user-input dottedLine">{{isTitleOther ? merchantBean.title : "" }}</span>
                    </div>
                </td>
                <td>
                  <table class="bold" style="background: #eee">
                      <td colspan="1">{{merchantBean.serviceTitle}}</td>
                      <td colspan="2">{{merchantBean.serviceBody}}</td>
                    </tr>
                    <tr>
                      <td colspan="3">X Signature <span class="user-input dottedLine"></span></td>
                    </tr>
                  </table>
                </td>
            </tr>
        </table>
        <hr>
        <hr>
        <!--  ( 9 ) PERSONAL GUARANTY -->
        <table border="0" cellpadding="10" cellspacing="0">
            <tr>
                <th style="text-align: left !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.pgVersion}}</th>
                <th colspan="3">(9) PERSONAL GUARANTY</th>
                <th  style="text-align: right !important; background: white !important; color: black !important; border: 1px solid black; font-size:11pt; font-size:1.1vmax;">{{merchantBean.version}}</th>
            </tr>
        </table>
        <table border="0" cellpadding="10" cellspacing="0">
            <tr>
                <td colspan="2" style="text-align: justify;">
                    {{merchantBean.personalGuaranty}} (the Guaranteed Parties) acceptance of the MPA and the General Terms and Conditions, the undersigned (“Guarantor”): (A) Unconditionally and irrevocably guarantees the full payment and performance of Merchant’s
                    obligations (i) as they now exist or as modified under the foregoing agreements, (ii) with or without actual notice of changes, and (iii) during and after the term of the agreements; (B) Waives notice of Merchant’s default; (C) Shall indemnify the Guaranteed Parties for any and all amounts due from Merchant; (D) Warrants, with knowledge that Guaranteed Parties are
                    acting in full reliance on the same, this Personal Guarantee of payment and not of collection; (E) Acknowledges that (i) the Guaranteed Parties may proceed in law directly against Guarantor and not Merchant, and (ii) this is a continuing personal guaranty and shall not be discharged or affected for any reason.</td>

                </td>
            </tr>
            <tr>
                <td>
                    <span class="bold">Signature</span>:
                    <div class="signature-box">
                        <canvas id="signature4" ng-mousemove="canMouseUp(4)" my-touchend="canMouseUp(4)" width="554" sketch></canvas>
                        <span ng-show="signature4Empty">Please sign in the box with mouse or finger.</span>
                        <a class="button" ng-hide="signature4Empty" ng-click="resetCanvas(4)">Clear Signature</a>
                    </div>
                    <p class="align-right">,an individual</p>
                </td>

            </tr>
        </table>
        <br>
    </div>

    <hr class="page-break">

    <!-- CONFIRMATION -->
    <div class="container" id="confirmation">
        <table border="0" cellpadding="10" cellspacing="0">
            <tr>
                <th style="text-align: left !important; background: black !important; color: white font-size:11pt; font-size:1.1vmax;">{{merchantBean.pgVersion}}</th>
                <th colspan="3">PART I: CONFIRMATION PAGE</th>
                <th></th>
            </tr>
        </table>
        <br>
        <div class="section">
            <table>
                <tr>
                    <td class="width-1">
                        <label><strong>PROCESSOR INFORMATION:</strong></label>
                    </td>
                    <td class="width-8">
                        <table class="border-bottom" cellpadding="2" cellspacing="0">
                            <tr>
                                <td class="width-6" colspan="5">
                                    <label>Name: </label>
                                    <span class="user-input">{{merchantBean.processor}}</span>
                                </td>
                            </tr>
                            <tr>
                                <td class="width-6" colspan="5">
                                    <label>Address: </label>
                                    <span class="user-input">{{merchantBean.processorAddress}}</span>
                                </td>
                            </tr>
                            <tr>
                                <td colspan="3">
                                    <label>URL: </label>
                                    <span class="user-input">{{merchantBean.processorUrl}}</span>
                                </td>
                                <td colspan="2">
                                    <label>Customer Service #: </label>
                                    <span class="user-input">{{merchantBean.processorCustomerService}}</span>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </div>
        <br>
        <table border="0" cellpadding="10" cellspacing="0">
            <tr style="text-align: justify;"><p><strong>Please read this entire Agreement. It describes the terms on which we will provide merchant processing Services to you. This summary provides answers to commonly asked questions about your Agreement.</strong></p></tr>
            <tr>
                <td style="text-align: justify;">
                    <p><strong>1. Your Discount Rates and other fees</strong> are calculated based on transactions qualifying for certain program pricing and interchange rates levied by the applicable Card Organization. Transactions that fail to qualify for these rates will be charged an additional fee. Interchange and program pricing levied by the Card Organization is subject to change, (see Section 6 of the General Terms & Conditions).</p>
                    <p><strong>2. We may debit your bank account</strong> (also referred to as your Settlement Account) for amounts owed to us.</p>
                    <p><strong>3. You are liable for Chargebacks and there are many reasons why a Chargeback may occur.</strong> When they occur we will debit your Settlement Account. See Section 8 of the General Terms & Conditions.</p>
                    <p><strong>4. If you wish to dispute any charge or funding,</strong> you must notify us within 60 days of the date of the statement on which the charge or funding appears.</p>
                    <p><strong>5. This Agreement limits our liability to you.</strong> See Section 10 of the General Terms & Conditions for further details.</p>
                </td>
                <td style="text-align: justify;">
                    <p><strong>6. We have assumed certain risks</strong> by agreeing to provide you with the Services. Accordingly, we may take certain actions to mitigate our risk, including termination of this Agreement, and holding monies otherwise payable to you (see Sections 16 and 17 of the General Terms & Conditions).</p>
                    <p><strong>7. By executing this Agreement with us</strong> you authorize us and our Affiliates to obtain and share financial and credit information regarding your business and the signers and guarantors of this Agreement until all your obligations to us and our Affiliates are satisfied.</p>
                    <p><strong>8. Arbitration:</strong> This Agreement contains a binding arbitration provision in Section 27 that affects your rights under this Agreement with respect to all Services.</p>
                </td>
            </tr>
        </table>
        <table class="border-bottom" cellpadding="2" cellspacing="0">
            <tr>
                <td class="width-10"></td>
            </tr>
        </table>
        <div class="section clearfix">
            <br>
            <table border="0" cellpadding="2" cellspacing="0" style="width: 45%; float:left; margin-right: 5%;">
                <tr>
                    <td><p><strong>Information about Bank:</strong></p></td>
                </tr>
                <tr>
                    <td>
                        <p>a) Your Bank, who is a Visa and MasterCard Member Bank, is {{merchantBean.sponsorBank}}(<strong>Bank</strong>), {{merchantBean.sponsorBankAddress}},{{merchantBean.sponsorBankCustServNumber}}.</p>
                        <p>b) Bank is the entity approved to extend acceptance of Visa and MasterCard products directly to you and will be a party to the sections of this Agreement listed in Section 2.2.</p>
                        <p>c) Bank works with Processor to provide the Services to you with respect to Visa Cards and to MasterCard Cards.</p>
                        <p>d) Bank shall, either directly or through Processor, advise you of pertinent Card Organization Rules with which you must comply.</p>
                        <p>e) Bank is responsible for and must provide settlement funds to you and will be responsible for all funds held in a reserve.</p>
                    </td>
                </tr>
            </table>
            <table border="0" cellpadding="2" cellspacing="0" style="width: 45%; float:left; margin-right: 5%;">
                <tr>
                    <td><p><strong>Your Responsibilities:</strong></p></td>
                </tr>
                <tr>
                    <td>
                        <p>a) You must comply in full at all times with this Agreement (including the Your Payments Acceptance Guide), all Card Organization Rules and all Cardholder and customer data security and storage requirements.
                        <p>b) You may view and download the Your Payments Acceptance Guide at
                            <a class="link" href="https://www.businesstrack.com" target="_blank">https://www.businesstrack.com</a>
                        <p>c) You may view and download the Interchange Qualification Matrix and American Express OptBlue® Guide at
                            <a class="link" href="https://www.businesstrack.com" target="_blank">https://www.businesstrack.com</a>
                        <p>d) You may download the Visa and MasterCard rules at: <a class="link" href="https://usa.visa.com/support/merchant.html" target="_blank">https://usa.visa.com/support/merchant.html</a> <a class="link" href="http://www.mastercard.com/us/merchant/support/rules.html" target="_blank">http://www.mastercard.com/us/merchant/support/rules.html</a>
                        <p>e) For your account to stay operational, you must keep fraud and Chargeback levels below Card Organization thresholds.
                        <p>f) Please retain a signed copy of your Agreement.
                    </td>
                </tr>
            </table>
        </div>
        <table border="0" cellpadding="10" cellspacing="0">
            <tr>
                <td>Print Merchant’s Business Legal Name: <span class="user-input">{{merchantBean.merchantBusinessBean.legalDbaName}}</span></td>
            </tr>
        </table>
        <br>
        <table border="0" cellpadding="10" cellspacing="0">
            <tr>
                <td colspan="2"><strong>By signing below, you:</strong></td>
            </tr>
            <tr>
                <td colspan="2">
                    <strong>
                        <p>&nbsp;&nbsp;(i)  confirm that you have received and read the Application, <a class="link" ng-click="agreementClicked = 'true'" href="{{merchantBean.s3PathForTerms}}" target="_blank">General Terms & Conditions</a> [version {{merchantBean.pgVersion}}, consisting of 10 pages including this Confirmation Page], [Interchange Rate Schedule]; and</p>
                        <p>&nbsp;&nbsp;(ii)  agree to all terms in this Agreement in your capacity as a person authorized to sign on behalf of the business set out in the Application.</p>
                        <p>&nbsp;&nbsp;(iii)  acknowledge that you have executed the Agreement using an electronic signature process and that signature reflects your agreement to be bound to the General Terms and Conditions set forth in the Agreement.</p>
                    </strong>
                </td>
            </tr>
            <tr>
                <td colspan="2"><strong>NO SALES REPRESENTATIVE IS AUTHORIZED TO ACCEPT OR AGREE TO ANY ALTERATIONS TO THIS AGREEMENT.</strong></td>
            </tr>
            <tr>
                <td>
                    <br>
                    <span class="bold">Business Principal</span>:
                    <div class="signature-box">
                        <canvas id="signature8" ng-mousemove="canMouseUp(8)" my-touchend="canMouseUp(8)"  ng-if="agreementClicked" sketch></canvas>
                        <canvas id="signature8" ng-if="!agreementClicked"></canvas>
                        <span ng-show="signature8Empty">Please sign in the box with mouse or finger.</span>
                        <a class="button" ng-hide="signature8Empty" ng-click="resetCanvas(8)">Clear Signature</a>
                    </div>
                    <p>Date: <span>{{signature8Date | date:'shortDate'}}</span></p>
                    <p>Print Name: <span class="user-input dottedLine">{{merchantBean.firstName}} {{merchantBean.lastName}}</span></p>
                    <div>
                        <span class="user-input">{{merchantBean.title ==="PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> President
                        <span class="user-input">{{merchantBean.title ==="VICE PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> Vice President
                        <span class="user-input">{{merchantBean.title ==="MEMBER LLC" ? "&#9746;" : "&#9744;" }}</span> Member L.L.C
                        <span class="user-input">{{merchantBean.title ==="OWNER" ? "&#9746;" : "&#9744;" }}</span> Owner
                        <span class="user-input">{{merchantBean.title ==="PARTNER" ? "&#9746;" : "&#9744;" }}</span> Partner
                        <span class="user-input">{{isTitleOther ? "&#9746;" : "&#9744;" }}</span> Other <span class="user-input dottedLine">{{isTitleOther ? merchantBean.title : "" }}</span>
                    </div>
                </td>
            </tr>
        </table>
        <table class="border-bottom" cellpadding="2" cellspacing="0">
            <tr>
                <td class="width-10"></td>
            </tr>
        </table>
        <p>{{merchantBean.pgVersion}}</p>
    </div>
    <!-- end #confirmation -->
    <hr class="page-break">
    <!-- start #lease -->
    <div class="container" id="lease" ng-show="isLeasedAgreement">
        <table border="0" cellpadding="2" cellspacing="0">
            <thead>
            <tr>
                <td colspan="3" class="align-center"><h1>EQUIPMENT LEASE AGREEMENT</h1></td>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td class="width-5" colspan="1">
                    Merchant #: <span class="user-input">N/A</span>
                </td>
                <td class="align-center width-5" colspan="1">
                    Sales Rep. Name: <span class="user-input"></span>
                </td>
                <td class="align-right width-5" colspan="1">
                    Sales #: <span class="user-input"></span>
                </td>
            </tr>
            </tbody>
        </table>
        <hr>
        <!-- (1) MERCHANT INFORMATION -->
        <table border="0" cellpadding="0" cellspacing="0">
            <tbody><tr>
                <th class="width-8">MERCHANT INFORMATION</th>
            </tr>
            </tbody></table>
        <div class="section">
            <table class="border" cellpadding="2" cellspacing="0">
                <tbody><tr>
                    <td class="width-5" colspan="5">
                        <label>Corporate Business Name</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.legalDbaName}}</span>
                    </td>
                    <td class="width-2" colspan="2">
                        <label>DBA Name</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.dbaName}}</span>
                    </td>
                </tr>
                <tr>
                    <td class="width-2" colspan="2">
                        <label>Business Address:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessAddress}}</span>
                    </td>
                    <td colspan="1">
                        <label>City:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessCity}}</span>
                    </td>
                    <td colspan="1">
                        <label>Country:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessCountry}}</span>
                    </td>
                    <td colspan="1">
                        <label>State:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessState}}</span>
                    </td>
                    <td colspan="1">
                        <label>Zip:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessZipcode}}</span>
                    </td>
                    <td colspan="1">
                        <label>Your Business Phone:</label>
                        <span class="user-input">{{merchantBean.merchantBusinessBean.businessPhoneNumber}}</span>
                    </td>
                </tr>
                <tr>
                    <td colspan="5">
                        <label>Business Type:</label>
                  <span class="user-input">
                       {{merchantBean.organizationTypeReferenceCode ==="I" ? "&#9746;" : "☐" }}
                  </span> Sole Ownership
                  <span class="user-input">
                      {{merchantBean.organizationTypeReferenceCode ==="P" ? "&#9746;" : "☐" }}
                  </span> Partnership
                  <span class="user-input">
                      {{merchantBean.organizationTypeReferenceCode ==="T" ? "&#9746;" : "☐" }}
                  </span> Non Profit/Tax Exempt
                  <span class="user-input">
                      {{merchantBean.organizationTypeReferenceCode ==="C" ? "&#9746;" : "☐" }}
                  </span> Public Corp.
                  <span class="user-input">
                      {{merchantBean.organizationTypeReferenceCode ==="PRC" ? "&#9746;" : "☐" }}
                  </span> Private Corp.
                  <span class="user-input">
                       {{merchantBean.organizationTypeReferenceCode ==="L" ? "&#9746;" : "☐" }}
                  </span>  L.L.C
                  <span class="user-input">
                      {{merchantBean.organizationTypeReferenceCode ==="G" ? "&#9746;" : "☐" }}
                  </span> Govt.
                    </td>
                    <td colspan="1">
                        <label>Tax ID#:</label>
                        <span class="user-input">{{maskDigit(merchantBean.merchantBusinessBean.employerIdNumberTax)}}</span>
                    </td>
                    <td colspan="1">
                        <label>Years in Business</label>
                        <span class="user-input">{{merchantBean.businessYearStarted}}</span>
                    </td>
                </tr>
                <tr>
                    <td class="width-2" colspan="2">
                        <label>Billing Address (if different from above):</label>
                        <span class="user-input">{{merchantBean.homeAddress}} {{merchantBean.homeAddress2 || ''}}</span>
                    </td>
                    <td colspan="1">
                        <label>City:</label>
                        <span class="user-input">{{merchantBean.city}}</span>
                    </td>
                    <td colspan="1">
                        <label>Country:</label>
                        <span class="user-input">{{merchantBean.country}}</span>
                    </td>
                    <td colspan="1">
                        <label>State:</label>
                        <span class="user-input">{{merchantBean.state}}</span>
                    </td>
                    <td colspan="2">
                        <label>Zip:</label>
                        <span class="user-input">{{merchantBean.zipCode}}</span>
                    </td>
                </tr>
                <tr>
                    <td class="width-2" colspan="3">
                        <label>Bank Name:</label>
                        <span class="user-input">{{merchantBean.instName || 'N/A'}}</span>
                    </td>
                    <td colspan="2">
                        <label>Routing Number:</label>
                        <span class="user-input">{{merchantBean.abaNumber}}</span>
                    </td>
                    <td colspan="2">
                        <label>Account Number:</label>
                        <span class="user-input">{{merchantBean.accountNumber}}</span>
                    </td>
                </tr>
                </tbody></table>
        </div>
        <hr>
        <!-- (2) DESCRIPTION OF LEASED EQUIPMENT -->
        <table border="0" cellpadding="0" cellspacing="0">
            <tbody>
            <tr>
                <th class="width-8">DESCRIPTION OF LEASED EQUIPMENT</th>
            </tr>
            </tbody>
        </table>
        <div class="section">
            <br>
            <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                <tbody><tr>
                    <th class="small">Equipment Type</th>
                    <th class="small">Quantity</th>
                    <th class="small align-right">Unit Price w/o Tax and S & H</th>
                </tr>
                <tr ng-repeat="lineItem in merchantBean.leaseEquipment">

                    <td> <span class='user-input dottedLine'> <span>{{lineItem.modelName}} </span></span></td>
                    <td><span class="user-input dottedLine">{{lineItem.quantity}}</span></td>
                    <td class="align-right">$ <span class="user-input dottedLine"> {{(lineItem.unitPrice | currency : "")}}</span></td>
                </tr>
                </tbody></table>
        </div>
        <hr>
        <!-- (3) SCHEDULE OF PAYMENTS -->
        <table border="0" cellpadding="0" cellspacing="0">
            <tbody>
            <tr>
                <th class="width-8">SCHEDULE OF PAYMENTS</th>
            </tr>
            </tbody>
        </table>
        <div class="section">
            <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                <tbody><tr style="font-size: 13pt !important; line-height:130%; font-weight: bold;">
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;">Lease Term:</td>
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;" class="align-right"><span class="user-input dottedLine">{{merchantBean.leaseTerm}}</span> mos.</td>
                </tr>
                <tr style="font-size: 13pt !important; line-height:130%; font-weight: bold;">
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;">Total Monthly Lease Charge:<br><span class="small">(w/o taxes, late fees, or other charges that may apply)</span></td>
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;" class="align-right">$<span class="user-input dottedLine">{{merchantBean.totalMonthlyLeaseCharge}}</span></td>
                </tr>
                <tr style="font-size: 13pt !important; line-height:130%; font-weight: bold;">
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;">Total Cost To Lease:</td>
                    <td style="font-size: 14px !important; line-height:130%; font-weight: bold;" class="align-right">$<span class="user-input dottedLine">{{merchantBean.totalCostToLease}}</span></td>
                </tr>
                </tbody></table>
            <table cellpadding="2" cellspacing="0" style="border: 1px solid; border-top:0;">
                <tbody><tr>
                    <td colspan="2">
                        <strong>Annual tax handling fee:</strong>
                    </td>
                </tr>
                <tr>
                    <td>AL, AR, CA, CT, GA, IN, KY, LA, MS,
                        MO, NE, NV, NM, NC, OK, OR, RI, SC,
                        TN, TX, VT, VA, WA, WV, WI, WY</td>
                    <td class="align-right">$<span class="user-input dottedLine">30.20</span></td>
                </tr>
                <tr>
                    <td>All other states</td>
                    <td class="align-right">$<span class="user-input dottedLine">10.20</span></td>
                </tr>
                </tbody></table>
            <table cellpadding="2" cellspacing="0" style="border: 1px solid; border-top:0;">
                <tbody><tr>
                    <td>Approx. Date of First ACH Payment:</td>
                    <td class="align-right"><span class="user-input dottedLine">1st of the following month</span></td>
                </tr>
                <tr>
                    <td>Approx. Amount of First ACH Payment:</td>
                    <td class="align-right">$<span class="user-input dottedLine">{{merchantBean.totalMonthlyLeaseCharge}}</span></td>
                </tr>
                </tbody></table>
        </div>
        <hr>
        <table border="0" cellpadding="10" cellspacing="0">
            <tbody><tr>
                <td style="text-align: justify;">This Equipment Lease Agreement (“Agreement”) is being entered into by and between First Data Merchant Services LLC and the Lessee identified in the signature panel of this Agreement. In this Agreement, the words “we,” “our” and “us” refer to First Data Merchant Services LLC and its successors and assigns and the words “you” and “your” refer to Lessee and its permitted successors and assigns. This Equipment Lease Agreement may be a factor in the pricing you are receiving for processing services provided by us.</td>
            </tr>
            <tr>
                <td style="text-align: justify;">
                    <p><span style="text-decoration: underline;">1. EffectiveDate,Term and Interim Rent.</span></p>
                    <p>a) This Agreement becomes effective on the date we deliver any piece of Equipment to you (the “Delivery Date”).
                        This Agreement remains in effect until all of your obligations and all of our obligations under it have been satisfied. We will deliver the Equipment to the site designated by you.</p>
                    <p>b) <span style="text-decoration: underline;">Term</span>: The term of this Agreement begins on a date designated by us after receipt of all required documentation and acceptance by us represented by our delivery of Equipment to you (the “Commencement Date”), and continues for the number of months indicated above in the Lease Term. YOU AGREE THIS AGREEMENT IS A NON- CANCELLABLE COMMITMENT BY YOU TO LEASE THE EQUIPMENT IDENTIFIED HEREIN FOR THE ENTIRE LEASE TERM INDICATED ABOVE. You agree to pay all amounts due during the Lease Term and confirm upon execution the Lease Term is specifically defined as written above.</p>
                    <p>d) You agree to pay an Interim Lease Payment in the amount of one-thirtieth (1/30th) of the monthly lease charge for each day from and including the Delivery Date until the date preceding the Commencement Date.</p>
                    <p>2. <span style="text-decoration: underline;">Authorization</span>. Lessee hereby authorizes us or our designees, successors or assigns (hereinafter “Lessor”) to with- draw any amounts including any and all sales taxes now due or hereinafter imposed, owed by Lessee in conjunction with this Agreement by initiating debit entries to Lessee’s account at the bank named above (hereinafter “Bank”), or such other bank as the Lessee may from time to time use. In the event of default of Lessee’s obligation hereunder, Lessee authorizes debit of its account for the full amount due under this Agreement. Further, Lessee authorizes Bank to accept and to charge any debit entries initiated by Lessor to Lessee’s account. In the event that Lessor withdraws funds erroneously from Lessee’s account, Lessee authorizes Lessor to credit Lessee’s account for an amount not to exceed the original amount of the debit. This authorization is to remain in full force and effect until Lessor and Bank have received written notice from Lessee of its termination in such time and in such manner as to afford Lessor and Bank a reasonable opportunity to act.</p>
                    <p>3. <span style="text-decoration: underline;">Default;Remedies.</span></p>
                    <p>a) If any debit of your bank account initiated by us is rejected when due, or if you otherwise fail to pay us any amounts due hereunder when due, or if you default in any material respect in the performance or observance of any obligation or provision of this Agreement or any agreement with any of our affiliates, alliances or joint ventures, any such event shall be a default hereunder. Without limiting the foregoing, any default by you under a Merchant Processing Agreement (“MPA”) with us or with an alliance or joint venture to which we are a party may be treated as a default under this Agreement. Such a default would include a default resulting from early termination of the MPA, if applicable. For fees that may be applicable upon payment default, please see paragraph 10.</p>
                    <p>b) Upon the occurrence of any default, we may at our option, effective immediately without notice, either (i) terminate this Agreement and our future obligations under this Agreement, repossess the Equipment and proceed in any lawful manner against you for collection of all charges that have accrued and are due and payable, or (ii) accelerate the remaining payments due, which shall be calculated as ninety-five (95%) of the product of (1) your monthly payment and (2) the number of months then outstanding on the Lease Term. If Equipment has not been returned this accelerated amount shall include the then fair market value of the Equipment (as determined in good faith by us). This acceleration of payments is not a penalty but liquidated damages for our loss of the bargain. Upon any such termination for default, we may proceed in any lawful manner to obtain satisfaction of the amounts owed to us and, if applicable, our recovery of the Equipment, including entering onto your premises to recover the Equipment. In addition, you shall also be responsible for our costs of collection, court costs and reasonable attorneys’ fees, as well as applicable shipping, repair and refurbishing costs of recovered Equipment. You agree that we shall be entitled to recover any amounts due to us under this Agreement by charging your bank account or any other funds of yours that come into our possession or control, or within the possession or control of our affiliates, alliances or joint ventures, or by setting off amounts that you owe to us against any amounts we may owe to you, without notifying you prior to doing so. Without limiting the foregoing, you agree that we are entitled to recover amounts owed to us under this Agreement by obtaining directly from an alliance or joint venture to which we are a party and with which you have entered into a MPA any funds held or available as security for payment under the terms of the MPA, including funds available under the “Reserve Account; Security Interest” section of the MPA, if applicable.</p>
                    <p>4. <span style="text-decoration: underline;">Return or Purchase of Equipment at End of Lease Period.</span> Upon the completion of your Lease Term the Agreement shall continue on a month-to-month basis. There is no obligation to continue the lease after the Lease Term ends. At the end of your Lease Term, you will have the option to: (a) return the Equipment to us; (b) purchase the Equipment from us for the lesser of fair market value at the time (as determined in good faith by us), or an amount equal to ten-percent (10%) of the total lease payments under this Lease Agreement with respect to each item of Equipment; or (c) as noted, rent the Equipment on a month-to-month basis at the existing monthly lease payment. In the absence of an affirmative election by you to return or purchase the Equipment, (c) will apply and this Agreement will continue on a month-to-month basis at the existing monthly lease payment. After the end of the Lease Term, if you do not want to continue to rent the Equipment on a month-to-month basis, then you will be obligated to provide Lessor with notice of that choice prior to the end of the Lease Term and advise whether you will return the Equipment to Lessor or purchase the Equipment, which price Lessor shall provide to you upon receipt of the notification. If you fail to provide such notice at least thirty (30) days prior to the end of the Lease Term, you acknowledge that Lessor may not have time to suspend billing due for the next month’s lease charge. If we terminate this Agreement pursuant to paragraph 3 due to a default by you, then you shall immediately return the Equipment to us at the address set forth in paragraph 11 no later than the tenth Business Day after termination, or remit to us the fair market value of the Equipment which amount we shall provide after good faith determination. We may collect any amounts due to us under this paragraph 4 by debiting your Settlement Account, and to the extent we are unable to obtain full satisfaction in this manner, you agree to pay the amounts owed to us promptly upon our request.</p>
                    <p>5. <span style="text-decoration: underline;">Limitation on Liability.</span> We are not liable for any loss, damage or expense of any kind or nature caused directly or indirectly by the Equipment, including any damage or injury to persons or property caused by the Equipment. We are not liable for the use or maintenance of the Equipment, its failure to operate, any repairs or service to it, or by any interruption of service or loss of use of the Equipment or resulting loss of business. Our liability arising out of or in any way connected with this Agreement shall not exceed the aggregate lease amount paid to us for the particular Equipment involved. In no event shall we be liable for any indirect, incidental, special or consequential damages. The remedies available to you under this Agreement are your sole and exclusive remedies.</p>
                    <p>6. <span style="text-decoration: underline;">Governing Law; Dispute Resolution; Miscellaneous.</span> This Agreement shall be governed by and will be construed in accordance with the laws of the State of New York (without applying its conflicts of laws principles). We have substantial facilities in the State of New York and many of the services provided under this Agreement are provided from these facilities. The exclusive venue for any actions or claims arising under or related to this Agreement shall be the appropriate state or federal court located in Suffolk County New York. If any part of this Agreement is not enforceable, the remaining provisions will remain valid and enforceable.</p>
                    <p>7. <span style="text-decoration: underline;">Equipment and Software.</span></p>
                    a) We agree to lease to you and you agree to lease from us the equipment identified on the first page of this Agreement or such other comparable equipment we provide you (the “Equipment”), according to the terms and conditions of this Agreement. Such Equipment may include CloverTM branded devices used in connection with the Clover devices (“Clover Devices”) or other equipment or peripherals compatible with Clover Devices (e.g. receipt printers or cash drawers).<p></p>
                    <p>b) For the avoidance of doubt, each Clover Device includes (i)operating software and (ii)the then-current, Clover standard object code version of software resident on or accessible through a Clover Device at the time we provide you with the Clover Device (“Clover Software”), but Clover Software does not include any software that may be obtained by you separately from using the Clover Device (e.g., from the CloverTM App Market).</p>
                    <p>c) We are providing the Equipment to you “as is” and make no representations or warranties of any kind as to the suitability of the Equipment for any particular purpose.</p>
                    <p>d) YOU ACKNOWLEDGE THAT THE EQUIPMENT YOU LEASE UNDER THIS LEASE AGREEMENT MAY NOT BE COMPATIBLE WITH ANOTHER PROCESSOR’S SYSTEMS AND THAT WE DO NOT HAVE ANY OBLIGATION TO MAKE SUCH EQUIPMENT COMPATIBLE IN THE EVENT THAT YOU ELECT TO USE ANOTHER SERVICE PROVIDER. UPON TERMINATION OF YOUR MERCHANT PROCESSING AGREE- MENT, YOU ACKNOWLEDGE THAT YOU MAY NOT BE ABLE TO USE THE EQUIPMENT LEASED UNDER THIS LEASE AGREEMENT WITH SAID SERVICE PROVIDER.
                    </p><p>8. <span style="text-decoration: underline;">Warranties.</span></p>
                    <p>a) All warranties express or implied, made to you or any other person are hereby disclaimed including without limitation, any warranties regarding quality, suitability, merchantability, fitness for a particular use, quiet enjoyment, or infringement.
                    </p><p>b) YouwarrantthatyouwillonlyusetheEquipmentforcommercialpurposesandwillnotusetheEquipmentfor any household or personal purposes.
                </p><p>c) LeasedEquipmentiswarrantedagainstmaterialdefectsforthelifeofthelease.Thiswarrantydoesnotinclude damage to the Equipment resulting from accident or misuse or any other breach of the Agreement. If the Equipment should become defective within the warranty period, First Data Merchant Services LLC will replace it free of charge (except that appropriate shipping charges may apply).</p>
                    <p>9. <span style="text-decoration: underline;">Lease Guaranty.</span> No guarantor shall have any right of subrogation to any of our rights in the Equipment or this Lease or against you, and any such right of subrogation is hereby waived and released. All indebtedness that exists now or arises after the execution of this Agreement between you and any guarantor is hereby subordinated to all of your present and future obligations, and those of your guarantor, to us, and no payment shall be made or accepted on such indebtedness due to you from a guarantor until the obligations due to us are paid and satisfied in full.</p>
                    <p>10. <span style="text-decoration: underline;">Payment of Amounts Due, Administrative and Collection Fees.</span></p>
                    a)
                    <table cellpadding="2" cellspacing="0" style="border: 1px solid;">
                        <tbody><tr>
                            <th colspan="2" class="small">SCHEDULE OF FEES
                            </th></tr>
                        <tr>
                            <td colspan="2"><strong>Default Fees</strong></td>
                        </tr>
                        <tr>
                            <td>NSF Fee</td>
                            <td class="align-right">$10</td>
                        </tr>
                        <tr>
                            <td>Collection Fee</td>
                            <td class="align-right">$25</td>
                        </tr>
                        <tr>
                            <td>Late Fee</td>
                            <td class="align-right">$10</td>
                        </tr>
                        <tr>
                            <td>Collection Invoicing Fee</td>
                            <td class="align-right">$7</td>
                        </tr>
                        <tr>
                            <td>Improper Return Fee</td>
                            <td class="align-right">$100*</td>
                        </tr>
                        </tbody></table>
                    <table cellpadding="2" cellspacing="0" style="border: 1px solid; border-top:0;">
                        <tbody><tr>
                            <td colspan="2"><strong>Administrative Fees</strong></td>
                        </tr>
                        <tr>
                            <td>Upgrade Fee</td>
                            <td class="align-right">$50</td>
                        </tr>
                        <tr>
                            <td>Assumption Fee</td>
                            <td class="align-right">$150</td>
                        </tr>
                        <tr>
                            <td>Lease Copy Fee</td>
                            <td class="align-right">$7</td>
                        </tr>
                        </tbody></table>
                    <p>b) The monthly lease charge is due and payable on the same day of each successive month thereafter of the Lease Term for each piece of lease Equipment. You agree to pay all assessed costs for delivery and installation of Equipment.</p>
                    <p>c) In addition to the monthly lease charge, you shall pay, or reimburse us for, amounts equal to any taxes or assessments on or arising out of this Agreement or the Equipment, and related supplies or any services, use or activities hereunder, including without limitation, state and local sales, use, property, privilege and excise tax, exclusive, however, of taxes based on our net income. Reimbursement of property tax calculation is based on an average tax rate.</p>
                    <p>d) Your lease payments will be due despite dissatisfaction for any reason with the Equipment or related processing services.</p>
                    <p>e) Whenever any payment is not made by you in full when due, you shall pay us a late fee of $10.00 for each month during which it remains unpaid but in no event more than the maximum permitted by law. You shall also pay to us a NSF fee of $10.00 for any debit we attempt to make against your bank account that is for any reason rejected, but in no event more than the maximum amount permitted by law.</p>
                    <p>f) In the event your account is placed into collections for past due lease amounts, you agree that we can recover a collection expense fee of $25 for each aggregate payment requiring a collection effort, but in no event more than the maximum amount permitted by law.</p>
                    <p>g) * See paragraph 11(g) for details regarding this fee.</p>

                    <p>11. <span style="text-decoration: underline;">Use and Return of Equipment; Insurance.</span></p>
                    <p>a) You shall cause the Equipment to be operated by competent and qualified personnel in accordance with any</p>
                    operating instructions furnished by us or the manufacturer. You shall maintain the Equipment in good operating condition and protect it from deterioration, normal wear and tear excepted.<!--
<p-->b) You shall not permit any physical alteration or modification of th eEquipment , or change the installation site of
                    the Equipment, without our prior written consent.<p></p>
                    <p>c) You shall not create, incur, assume or allow any consensually or judicially imposed liens or encumbrances on ,or part with possession of, or sublease the Equipment without our prior written consent.</p>
                    <p>d) You shall comply with all governmental laws, rules and regulations relating to the use of the Equipment. You are
                        also responsible for obtaining all permits required to operate the Equipment at your facility.</p>
                    <p>e) We or our representatives may, at any time, enter your premises for purposes of inspecting, examining or repairing the Equipment.</p>
                    <p>f) The Equipment shall remain our personal property and shall not under any circumstances be considered to be a fixture affixed to your real estate. You shall permit us to affix suitable labels or stencils to the Equipment evidencing our ownership.</p>
                    <p>g) You agree that all Equipment returns shall be to TASQ Technology, 1169 CantonRoad, Marietta, GA., 30066, be done in a manner that can be tracked, and shall have Lease number referenced on the return packaging. You understand and agree that your failure to return the Equipment in the manner noted in the preceding sentence will delay our receipt of the return and possibly result in you being charged $100. If returned Equipment shows excessive wear and tear or is not in good operating condition (in each case, as determined by us in our reasonable discretion), you will be charged our cost to restore such Equipment to normal or good operating condition, as applicable.</p>
                    <p>h) You shall keep the Equipment adequately insured against loss by fire, theft, and all other hazards.</p>
                    <p>i) You shall provide proof of insurance as evidenced by a certificate naming First Data Merchant Services LLC as a loss payee under your insurance policy. The loss, destruction, theft or damage of or to the Equipment shall not relieve you from your obligation to pay the full purchase price or total monthly lease charges hereunder.</p>
                    <p>12. <span style="text-decoration: underline;">Site Preparation.</span> You will prepare the installation site(s) for the Equipment, including but not limited to the power supply circuits and phone lines, in conformance with the manufacturer’s and our specifications and will make the site(s) available to us by the confirmed shipping date.</p>
                    <p>13. <span style="text-decoration: underline;">Title to Equipment.</span> We at all times retain title to the Equipment unless we agree otherwise in writing. You agree to execute and deliver to us any statement or instrument that we may request to confirm or evidence our ownership of the Equipment, and you irrevocably appoint us as your attorney-in-fact to execute and file the same in your name and on your behalf. If a court determines that the leasing transaction contemplated by this Agreement does not constitute a financing and is not a lease of the Equipment, then we shall be deemed to have a first lien security interest on the Equipment as of the date of this Agreement, and you will execute such documentation as we may request to evidence such security interest.</p>
                    <p>14. <span style="text-decoration: underline;">Software License.</span> We retain all ownership and copyright interest in and to all computer software, related documentation, technology, know-how and processes embodied in or provided in connection with the Equipment (“FD Software”) other than computer software, related documentation, technology, know-how and processes owned or licensed by the manufacturer of the Equipment (“Manufacturer Software”). Manufacturer Software together with the FD Software is collectively referred to as “Software”. You shall have only a nonexclusive license to use the Software in your operation of the Equipment. Notwithstanding the foregoing, ownership and copyright right interest in and to the Clover Software and your license to use the Clover Software and the Clover services is described in and governed by the terms of your MPA or in a separate agreement.
                    </p><p>15. <span style="text-decoration: underline;">Indemnification.</span> You shall indemnify and hold us harmless from and against any and all losses, liabilities, damages and expenses, (including attorneys’ fees) resulting from (a) the operation, use, condition, liens against, or return of the Equipment or (b) any breach by you of any of your obligations hereunder, except to the extent any losses, liabilities, damages or expenses result from our gross negligence or willful misconduct.</p>
                    <p>16. <span style="text-decoration: underline;">Assignment.</span> You may not assign or transfer this Agreement, by operation of law or otherwise, without our prior written consent. For purposes of this Agreement, any transfer of voting control of you or your parent shall be considered an assignment or transfer hereof. We may assign or transfer this Agreement and our rights and obligations hereunder, in whole or in part, to any third party without the necessity of obtaining your consent.</p>
                    <p>17. <span style="text-decoration: underline;">Notices.</span> All notices must be in writing, if to you at your address appearing on the cover page of this Agreement and if to us at 4000 Coral Ridge Drive, Coral Springs, Florida, 33065. Attn: Lease Department, and shall be deemed to have been given (i) if sent by mail or courier, upon the earlier of five (5) days after mailing or when actually received or, in the case of courier, when delivered, and (ii) if sent by facsimile machine, when the courier confirmation copy is actually received. Notice given in any other manner shall be effective when actually received, if to you at the address appearing on the cover page of this Agreement or by any electronic means, including but not limited to the email address you have provided on the cover page of the Agreement. Notices sent to the Merchant’s last known address, as indicated in our records, shall constitute effective notice to the Merchant under this Agreement. Customer Service toll free number 1-877-257-2094.</p>
                    <p>18. <span style="text-decoration: underline;">Entire Agreement.</span> This Agreement constitutes the entire agreement between the parties with respect to its subject matter, supersedes any previous agreements and understandings and can be changed only by a written agreement signed by all parties. This Agreement may be executed in any number of counterparts and all of such counterparts taken together shall be deemed to constitute one and the same instrument. Delivery of an executed counterpart of a signature page of this Agreement by facsimile shall be effective as delivery of a manually executed counterpart of this Agreement.</p>
                </td>
            </tr>
            </tbody></table>
        <hr>
        <table border="0" cellpadding="10" cellspacing="0">
            <tbody><tr>
                <th colspan="2">LEASE ACCEPTANCE</th>
            </tr>
            <tr>
                <td colspan="2" style="text-align: justify;">Undersigned agrees to all terms and conditions contained in this Equipment Lease Agreement. Lessee authorizes First Data Merchant Services LLC or its agents, to request and obtain from a consumer reporting agency personal and business consumer reports. Each of the undersigned authorizes us to obtain subsequent consumer reports in connection with the maintenance, updating, renewal or extension of the Agreement. Each of the undersigned furthermore agrees that all references, including banks and consumer reporting agencies, may release any and all personal and business credit financial information to us. <strong><span style="text-decoration: underline;">THIS LEASE IS A NON-CANCELLABLE COMMITMENT BY YOU FOR THE FULL LEASE TERM INDICATED HEREIN.</span></strong> By executing the below, Lessee confirms that the Lease Term is filled in above.Any attempt by you to terminate this commitment prior to the end of the Lease Term, entitles First Data Merchant Services LLC to all rights and remedies set forth in paragraph 3 including acceleration of the remaining payments due, which shall be calculated as 95% of the product of (1) your monthly payment and (2) the number of months then outstanding on the Lease Term. BY SIGNING BELOW, YOU ARE AGREEING TO THE TERMS AND CONDITIONS IN THIS AGREEMENT AND ACKNOWLEDGING PROCESSOR’S ACCEPTANCE OF THIS AGREEMENT. IF YOU SIGN USING AN ELECTRONIC SIGNATURE PROCESS, THAT SIGNATURE REFLECTS YOUR AGREEMENT TO BE BOUND BY THE TERMS AND CONDITIONS IN THIS AGREEMENT.</td>
            </tr>
            <tr>
                <td>
                    <div class="signature-box">
                        <canvas id="signature6" ng-mousemove="canMouseUp(6)" my-touchend="canMouseUp(6)" sketch></canvas>
                        <span ng-show="signature6Empty">Please sign in the box with mouse or finger.</span>
                        <a class="button" ng-hide="signature6Empty" ng-click="resetCanvas(6)">Clear Signature</a>

                    </div>
                    <p>Date: <span class="user-input dottedLine">{{signature6Date | date:'shortDate'}}</span></p>
                    <p>Print Name: <span class="user-input dottedLine">{{merchantBean.firstName}} {{merchantBean.lastName}}</span></p>
                    <div>
                        <span class="user-input">{{merchantBean.title ==="PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> President
                        <span class="user-input">{{merchantBean.title ==="VICE PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> Vice President
                        <span class="user-input">{{merchantBean.title ==="MEMBER LLC" ? "&#9746;" : "&#9744;" }}</span> Member L.L.C
                        <span class="user-input">{{merchantBean.title ==="OWNER" ? "&#9746;" : "&#9744;" }}</span> Owner
                        <span class="user-input">{{merchantBean.title ==="PARTNER" ? "&#9746;" : "&#9744;" }}</span> Partner
                        <span class="user-input">{{isTitleOther ? "&#9746;" : "&#9744;" }}</span> Other <span class="user-input dottedLine">{{isTitleOther ? merchantBean.title : "" }}</span>
                    </div>
                </td>
                <td></td>
            </tr>
            </tbody></table>
        <hr>
        <table border="0" cellpadding="10" cellspacing="0">
            <tbody><tr>
                <th colspan="2">PERSONAL GUARANTY</th>
            </tr>
            <tr>
                <td colspan="2" style="text-align: justify;">Undersigned unconditionally guarantees performance of this Equipment Lease Agreement by Lessee and payment of all sums due hereunder in the event of default, hereby waiving any modification, amendment or extension and notice thereof, and further agrees to the terms of this Equipment Lease Agreement insofar as they apply to the undersigned as guarantor. BY SIGNING BELOW, YOU ARE AGREEING TO THE TERMS AND CONDITIONS IN THIS AGREEMENT AND ACKNOWLEDGING PROCESSOR’S ACCEPTANCE OF THIS AGREEMENT. IF YOU SIGN USING AN ELECTRONIC SIGNATURE PROCESS, THAT SIGNATURE REFLECTS YOUR AGREEMENT TO BE BOUND BY THE TERMS AND CONDITIONS IN THIS AGREEMENT.</td>
            </tr>
            <tr>
                <td>
                    <span class="bold">Personal Guarantor’s Signature (No Title Allowed)</span>:
                    <div class="signature-box">
                        <canvas id="signature7" ng-mousemove="canMouseUp(7)" my-touchend="canMouseUp(7)" sketch class="disable"></canvas>
                        <span ng-show="signature7Empty">Please sign in the box with mouse or finger.</span>
                        <a class="button" ng-hide="signature7Empty" ng-click="resetCanvas(7)">Clear Signature</a>
                    </div>
                    <p class="align-right">,an individual</p>
                </td>
                <td>
                    <br>
                    <p>Date: <span class="user-input dottedLine">{{signature7Date | date:'shortDate'}}</span></p>
                    <p>Print Name: <span class="user-input dottedLine">{{merchantBean.firstName}} {{merchantBean.lastName}}</span></p>
                    <p>Home Phone Number: <span class="user-input dottedLine">{{merchantBean.merchantBusinessBean.phoneNumber}}</span></p>
                    <table class="border" cellpadding="0" cellspacing="0">
                        <tbody><tr>
                            <td colspan="2">
                                <label>Home Address:</label>
                                <span class="user-input">{{merchantBean.merchantBusinessBean.businessAddress}} {{merchantBean.merchantBusinessBean.businessAptSuite}}</span>
                            </td>
                            <td>
                                <label>City:</label>
                                <span class="user-input">{{merchantBean.merchantBusinessBean.businessCity}}</span>
                            </td>
                            <td>
                                <label>State:</label>
                                <span class="user-input">{{merchantBean.merchantBusinessBean.businessState}}</span>
                            </td>
                            <td>
                                <label>Zip:</label>
                                <span class="user-input">{{merchantBean.merchantBusinessBean.businessZipcode}}</span>
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2">
                                <label>DOB:</label>
                                <span class="user-input">{{merchantBean.dateOfBirth}}</span>
                            </td>
                            <td colspan="3">
                                <label>Social Security #:</label>
                                <span class="user-input">{{maskDigit(merchantBean.merchantBusinessBean.socialSecurityNumber)}}</span>
                            </td>
                        </tr>
                        </tbody></table>

                </td>
            </tr>
            </tbody></table>


    </div><!-- end #lease -->

    <hr>

    <div class="container screen">
        <div class="align-center">
            <!-- TODO: add link here or re-word -->
            <!--<div><input type="checkbox"  ng-model="readUnderstood" /> I have read and understood the entire <a class="link" href="#" target="_blank">Merchant Agreement</a> and Confirmation.</div>-->
            <br>
            <!--<a class="button blue" href="javascript:window.print();">Print PDF</a>-->
            <a class="button" ng-class="{'disabled': (isFormNotValid() || clickedTCSubmit)}" ng-click="isFormNotValid() || clickedTCSubmit || submitTC()"><i ng-show="clickedTCSubmit" class="fa fa-spinner fa-spin fa-lg fa-fw"></i>{{clickedTCSubmit ? ' Submitting...' : 'Submit'}}</a>
        </div>
    </div>

</div>

When the user clicks Submit, we invoke the submitTC() function. This function make a POST request to the POST Application/Submit endpoint and passes all relevant data as input.

 /**
     * submit Terms and Conditions
     * @method submitTC
     * @return
     */
    $scope.submitTC = function() {
      if ($scope.isFormNotValid()) return;
      $scope.clickedTCSubmit = true;

      var orderId = fdService.getOrderId() || $routeParams.orderID;
      if (!orderId) {
        $scope.clickedTCSubmit = false;
        return;
      }

      var sdata = {
        orderId: orderId,
      };
      sdata.signatures = [];

      for (var i = 0; i < $scope.totalSigns; i++) {
        if (!$scope.signatures[i].readOnly) {
          var canvas;
          if (!$scope.showSignBox()) {
            canvas = $scope.signCanvases[i + 1] ? $scope.signCanvases[i + 1] : null;
          } else {
            canvas = $document[0].getElementById('signature' + (i + 1));
          }
          var signature = canvas ? canvas.toDataURL().replace(/^data:image\/(png);base64,/, "") : 'NA';
          var name = $scope.signatures[i].type + '_' + $scope.signatures[i].position;
          sdata.signatures.push({
            name: name,
            ownerId: $scope.signatures[i].ownerId,
            signature: signature
          });
        }
      }

      //Audit trail information to backend
      var orderId = fdService.getOrderId();
      var cart = fdService.getOrderedCart(orderId);
      if (cart.shippingAddress.length > 0) {
        var cd = cart.shippingAddress[0];
        var merchantName = cd.firstname + ' ' + cd.lastname;
        var email = cd.email;
        var p = fdService.getGeoData();
        var langAndLat = p ? p.coords.latitude + ',' + p.coords.longitude : '';
        var acceptedAgreementDate = $scope.acceptedAgreementDate;
        sdata['contractAuditTrailRequestModel'] = {
          'merchantName': merchantName,
          'merchantEmail': email,
          'geoLocation': langAndLat,
          'signDate': new Date().toJSON(),
          'acceptedAgreementDate': new Date().toJSON()
        }
      }

      fdService.submitSignature(sdata)
        .success(function(data, status, headers, config) {
          fdService.clearOrderId();
          fdService.clearCart();
          fdService.clearOrderedCart();
          fdService.clearCategoryFromSession();
          fdService.clearTransactionInfo();
          fdService.clearAcquiringPricing();
          fdService.clearEquipmentPricing();
          $rootScope.cart = fdService.getCart();
          $location.path('/thankyou');
        })
        .error(function(data, status, headers, config) {
          $scope.clickedTCSubmit = false;
          $location.path('/400');
        });
    };


Almost done!

Next: Last step! Collect the merchant’s signature and Submit the Application.

Sign and Submit

Overview

API: POST Application/Submit

Check out the detailed API documentation of the POST Application/Submit API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

You’ve made it this far! Now that we’ve just about finished this tutorial, it’s time to have the merchant electronically sign and submit.

In this section, we’re going to handle just that!

How do I capture the signature?

The user’s signature needs to be submitted as an inlined image (png), encoded in base64. You can capture the signature using any library or plugin of your choosing.

Partial example user interface displaying the Signature Box and Submit Button Partial example user interface displaying the Signature Box and Submit Button

The below HTML defines the HTMl view we use to collect the user’s signature. This view allows the user to sign with their mouse or trackpad and submit a base64 version of that signature along with the request.

<!--  ( 8 ) AGREEMENT APPROVAL -->
<table border="0" cellpadding="5" cellspacing="0">
    <tr>
        <th>(8) AGREEMENT APPROVAL</th>
    </tr>
    <tbody style="text-align:justify;">
    <tr>
        <td><strong>On behalf of myself as an individual, and the entity on whose behalf I am signing, (A) I authorize [Servicers], the applicable Card / Payments Organizations, and its and their Affiliates, third party subcontractors and/or agents:</strong> (i) to use, disclose, and exchange amongst them, the information in the Agreement and information about me personally, (including by requesting, personal and business consumer reports, bank references, and other information as necessary from time to time), for marketing and administrative purposes, verification purposes, purposes under the Merchant Processing Application and Agreement (“MPA”), if approved, and any other uses permitted by law; (ii) to inform me directly about the contents of requested consumer reports (including the name and address of the agency furnishing the report), and (ii) to receive any and all personal and business credit financial information from all references, including banks and consumer reporting agencies, which are hereby released to provide that information; and (B) I certify that: (i) The federal taxpayer identification number and corresponding filing name provided herein are correct; (ii) The statements made and agreed to in this MPA, to which I have not made any alterations or stricken out any language, are true, complete and accurate, and may be relied upon as current unless changed or updated per the Notice provisions of Agreement; (iii) I can read and understand the English language; (iv) I have received and read a copy of the (a) MPA (consisting of Sections 1-9), (b) General Terms and Conditions, (c) Confirmation Page (version [{{merchantBean.pgVersion}}]), and (d) Interchange rate Schedule. I understand that the Interchange Qualification Matrix and American Express OptBlue® Guide and Your Payments Acceptance Guide are available at www.businesstrack.com and the signature below is for the entire contents of the listed documents; v) I have authority to bind the entity on whose behalf I am signing below; I further acknowledge and agree that I will not use my merchant account and/or the Services for illegal transactions, for example, those prohibited by the Unlawful Internet Gambling Enforcement Act, 31 U.S.C. Section 5361 et seq, as may be amended from time to time or for processing and acceptance of transactions in certain jurisdictions pursuant to 31 CFr Part 500 et seq. and other laws enforced by the Office of Foreign Assets Control (OFAC).</td>
    </tr>
    </tbody>
</table>
<table border="0" cellpadding="2" cellspacing="0">
    <tr>
        <td>
            <span class="bold">Merchant Business Principal:</span>
            <div class="signature-box">
                <canvas id="signature1" ng-mousemove="canMouseUp(1)" my-touchend="canMouseUp(1)" sketch></canvas>
                <span ng-show="signature1Empty">Please sign in the box with mouse or finger.</span>
                <a class="button" ng-hide="signature1Empty" ng-click="resetCanvas(1)">Clear Signature</a>
            </div>
            <p>Date: <span class="user-input dottedLine">{{signature1Date | date:'shortDate'}}</span></p>
            <p>Print Name: <span class="user-input dottedLine">{{merchantBean.firstName}} {{merchantBean.lastName}}</span></p>
            <div>
                <span class="user-input">{{merchantBean.title ==="PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> President
                <span class="user-input">{{merchantBean.title ==="VICE PRESIDENT" ? "&#9746;" : "&#9744;" }}</span> Vice President
                <span class="user-input">{{merchantBean.title ==="MEMBER LLC" ? "&#9746;" : "&#9744;" }}</span> Member L.L.C
                <span class="user-input">{{merchantBean.title ==="OWNER" ? "&#9746;" : "&#9744;" }}</span> Owner
                <span class="user-input">{{merchantBean.title ==="PARTNER" ? "&#9746;" : "&#9744;" }}</span> Partner
                <span class="user-input">{{isTitleOther ? "&#9746;" : "&#9744;" }}</span> Other <span class="user-input dottedLine">{{isTitleOther ? merchantBean.title : "" }}</span>
            </div>
        </td>
        <td>
          <table class="bold" style="background: #eee">
              <td colspan="1">{{merchantBean.serviceTitle}}</td>
              <td colspan="2">{{merchantBean.serviceBody}}</td>
            </tr>
            <tr>
              <td colspan="3">X Signature <span class="user-input dottedLine"></span></td>
            </tr>
          </table>
        </td>
    </tr>
</table>

When the user clicks Submit, we invoke the submitTC() function. This function makes a POST request to the POST Application/Submit endpoint and passes all relevant data as input.

 /**
     * submit Terms and Conditions
     * @method submitTC
     * @return
     */
    $scope.submitTC = function() {
      if ($scope.isFormNotValid()) return;
      $scope.clickedTCSubmit = true;

      var orderId = fdService.getOrderId() || $routeParams.orderID;
      if (!orderId) {
        $scope.clickedTCSubmit = false;
        return;
      }

      var sdata = {
        orderId: orderId,
      };
      sdata.signatures = [];

      for (var i = 0; i < $scope.totalSigns; i++) {
        if (!$scope.signatures[i].readOnly) {
          var canvas;
          if (!$scope.showSignBox()) {
            canvas = $scope.signCanvases[i + 1] ? $scope.signCanvases[i + 1] : null;
          } else {
            canvas = $document[0].getElementById('signature' + (i + 1));
          }
          var signature = canvas ? canvas.toDataURL().replace(/^data:image\/(png);base64,/, "") : 'NA';
          var name = $scope.signatures[i].type + '_' + $scope.signatures[i].position;
          sdata.signatures.push({
            name: name,
            ownerId: $scope.signatures[i].ownerId,
            signature: signature
          });
        }
      }

      //Audit trail information to backend
      var orderId = fdService.getOrderId();
      var cart = fdService.getOrderedCart(orderId);
      if (cart.shippingAddress.length > 0) {
        var cd = cart.shippingAddress[0];
        var merchantName = cd.firstname + ' ' + cd.lastname;
        var email = cd.email;
        var p = fdService.getGeoData();
        var langAndLat = p ? p.coords.latitude + ',' + p.coords.longitude : '';
        var acceptedAgreementDate = $scope.acceptedAgreementDate;
        sdata['contractAuditTrailRequestModel'] = {
          'merchantName': merchantName,
          'merchantEmail': email,
          'geoLocation': langAndLat,
          'signDate': new Date().toJSON(),
          'acceptedAgreementDate': new Date().toJSON()
        }
      }

      fdService.submitSignature(sdata)
        .success(function(data, status, headers, config) {
          fdService.clearOrderId();
          fdService.clearCart();
          fdService.clearOrderedCart();
          fdService.clearCategoryFromSession();
          fdService.clearTransactionInfo();
          fdService.clearAcquiringPricing();
          fdService.clearEquipmentPricing();
          $rootScope.cart = fdService.getCart();
          $location.path('/thankyou');
        })
        .error(function(data, status, headers, config) {
          $scope.clickedTCSubmit = false;
          $location.path('/400');
        });
    };


Next Steps

In this section we discussed how to invoke the POST Application/Submit endpoint when the finish button is clicked. Great work!

Marketplace For PFACs

A payment facilitator (PFAC) is a third party agent that is authorized by the card networks to aggregate transactions and submit them to Fiserv on behalf of a community of sub-merchants. Payment Facilitators (PFAC) have the ability to streamline the signup, onboarding, credit decisioning and fulfillment of a merchant account through the Marketplace APIs. Fiserv supports both aggregator and multi-MID models. We will fund either the PFAC or the sub-merchant depending on your business model. The single MID model is not supported on the boarding API.

For PFAC, a company signs up with our backend payment processing systems to sign-up its merchants for a percentage of their revenue.

Have questions about our APIs?

Check out our detailed API documentation.

The tutorial below gives an idea how to create a PFAC merchant order, validate product data and merchant information. Please refer to our technical API documentation for a detailed expanation on API’s used.

Environment Setup

What is Node?

Node is an executable version of Chrome’s V8 JavaScript engine that allows you to write JavaScript code on the server.

What is Express.js?

Express.js is a powerful web framework which helps with setting up routes for npm projects.

What is react.js?

React is an open-source JavaScript library for building user interfaces specifically for single page applications.

PFAC environment setup is similar to the Marketplace Environment. You would need to install latest Node and Express libraries.

Various technologies and frameworks exist for developing backend applications. We chose Node for this tutorial because of its ease of use to setup and install.

This PFAC demo app is built using React JavaScript library and Express, a web application framework for Node.js. Express acts as a proxy server to call actual First Data APIs.

React, by default runs its server on port 3000, and we have decided to use the same port. In order to start the front end/react server, go to the path where the project has been downloaded, and start the server with command npm start in a separate terminal.

Keep in mind that, we need two separate terminals with servers running on it, one for express and the other for react which does module bundling and task running in background.

Application Setup

Download the repo

Download the FD Marketplace sample app on GitHub or view it live here.

Our PFAC Demo app is open sourced and free to download on GitHub. Throughout this tutorial, we’ll break down how this app works and the process involved in extending it to fit your needs. Feel free at any time to customize this app accordingly.

Please make sure you have cloned or downloaded the PFAC Demo Marketplace projects from GitHub before proceeding.

Now that you have Node (and npm which is packaged with Node) set up on your local machine, it is time to take a look at the PFAC Demo App.

Using the terminal app, type cd (also known as change directory) and change your path to Pfac-demo.

We’re going to install all the dependencies required for this app. To do so, type npm install --save to install and save all the dependencies.

This command retrieves a list of packages from a file called package.json. The npm install command then installs the relevant packages accordingly so your computer can compile and run the app. If you don’t see any errors, you’re good to go.

To run/start the PFAC Demo App, type npm start.

Authentication

Why do we Require Authentication?

In one word: security. Numerous high level credit card breaches have increased the need for more advanced cryptography standards to protect credit card holders. The Payment Card Industry Data Security Standard (PCI DSS) - an information security standard used by all the major credit card networks - requires merchants to encrypt specific card holder information. Using HMAC Authentication is a standard method of protecting this sensitive information.

In order to properly access and make calls to the First Data Marketplace APIs, you will need to authenticate your requests. To do so, you’ll need to generate HMAC authentication.

Please follow the steps mentioned in Marketplace Authentication to get access to First data API’s via sandbox to send and receive service requests.

In order to properly access and make calls to the First Data Marketplace APIs, you will need to authenticate your requests. To do so, you’ll need to generate HMAC authentication.

HMAC authentication, also known as hash-based message authentication code, is a cryptographic authentication scheme involving a hash function used in combination with a secret key.

To try any of the code in this tutorial, you can use your credentials for our Sandbox, sent to you via email. Don’t have credentials?

Sandbox

If you have not done so already, please request credentials from the sandbox and then replace the values in the `credentials.json` file with the credentials you received via email.

  1. Request Access to Sandbox

Next, you’ll need to add to your project a file called credentials.json at the same level with server.js file, with your new sandbox credentials (the same credentials you received via email). To do so, go to the root of the project folder you downloaded and open a file in a text editor of your choosing (we recommend Sublime Text or Atom, but feel free to use any editor you like). Add the following text into the file :

{
 "dev" : {
     "kongUrl" : "API_URL",
     "username" :  "API_username-xxxx-xxxx",
     "secret" : "API_secret-xxxx-xxxx"
 }
}

Just replace the values with actual values such as kongUrl, username and secret that you received in the email and save the file as credentials.json.

We’ve set the default port for express as 8080 in server.js, but feel free to change it to any other 4-digit port of your choosing. If you don’t edit this value, the app will run on the default port 8080.

Now type node server.js in the terminal, to start the express server. Now that we are done setting up express.js, we shall move on to react set up.

Example Request

Now that we have authenticated our API calls to the First Data Marketplace API, we can make a request using the getAuthenticationHeaders() function defined above. Please note that, to have API calls invoked, we use app.all call with express. This call acts as a gateway for all API calls from proxy to backend.

Please find an example of this. The same code is used PFAC demo app as well.


app.all('/marketplace/*', function(req, res) {
    var options = {
        method: req.method,
        url: credentials.kongUrl + req.originalUrl,
        headers: getAuthenticationHeaders()
      };
    if (req.method == 'POST') {
    options['json'] = req.body;
    options['content-type'] = 'application/json';
    }

    request(options, function(error, response, body) {
    if (error) throw new Error(error);
    res.status(response.statusCode).send(body);
    });
});

Also, here is the getAuthenticationHeaders() for reference.


// Set the headers
var getAuthenticationHeaders = function () {
    var date = new Date().toUTCString();
    var stringToSign = 'date: ' + date.trim();
    var encodedSignature = crypto.createHmac("sha1", credentials.secret).update(stringToSign).digest("base64");
    var hmacAuth = 'hmac username="' + credentials.username + '",algorithm="hmac-sha1",headers="date",signature="' + encodedSignature + '"';
    return {
      'date': date,
      'Authorization': hmacAuth
    }
}

Sign Up Page

Overview

To create a PFAC merchant order, all the required fields (the ones with red asterisk *) need to be filled out including the organization, the owner, the banking, and the billing information.

You will then select your preferred equipment by clicking on the ‘Add to Order’ button. And finally submit your order by clicking on continue button at the bottom of the page. It should become red after all the required information was filled out.

API: GET Products

Check out the detailed API documentation of the GET Products API endpoint and see example requests in Shell, Python, JavaScript, Java and PHP here.

Products API

Our API provides First Data-curated products, such as Clover products, partner payment terminals, partner software solutions, hardware accessories and more. s PFAC sign up page will display the products of type “Terminal”. Here is the code snippet, API call to get a product list:

export function getProductsList() {
    axios.get('/marketplace/v1/products').then(function(response) {  
        let products = response.data;
        products.forEach((prod) => {
            if(prod.productType === 'Terminal') {
                store.dispatch(getProducts(prod));
            }
        });
    });
}

And here is an html code to display a product:

<div className=" product column-2" key={c.id}>
    <div><img src={thumbUrl} /></div>
    <a className="button small add-to-order" onClick={this.addToOrder}>Add to Order</a>
</div>

Bank Routing Number Verification

To verify bank ABA or routing transfer number to identify specific financial institutions within the United States we use the following service:

export function verifyABARouting(data, successCbk, failureCbk) {
    axios.post('/marketplace/v1/banks/validate', data).then(
        function(response) {
            successCbk(response.data);
        },
        function(error) {
            failureCbk(error.response.data);
        }
    );
}

Submit Your Request

To place the order the payload is formed from all the data submitted and passed it to Sign-up service:

export function pfacSignup(data) {
    axios.post('/marketplace/v1/pfac/application/signup', data).then(function(response) {
        store.dispatch(updateOrder(response.data));
    });
}

with the sample payload, where “cartDetails” and “pricingDetails” are optional:

{
  "cartDetails": {
    "data": [
      {
        "id": 62808,
        "name": "NMI Gateway Gateway (Payment Connection)",
        "term": "P",
        "qty": "1",
        "productType": "Terminal"
      },
      {
        "id": 10031,
        "name": "Interchange+",
        "term": "P",
        "qty": 1,
        "productType": "ACQUIRING"
      }
    ],
    "amount": 0,
    "shipping_amount": 19.99,
    "tax": 0,
    "taxPercent": 0,
    "total": 0,
    "status": 0,
    "shipping_option_id": 1,
    "purchaseEnabled": true,
    "total_qty": 1
  },
  "pricingDetails": [
    {
      "productId": "2",
      "description": "Visa Qualified Credit",
      "feeMinAbsolute": 0,
      "feeMin": 0,
      "feeDefault": 0.15,
      "feeMax": 0,
      "feeMaxAbsolute": 0,
      "minAmountAbsolute": 0,
      "minAmt": 0,
      "defaultAmt": 0,
      "maxAmt": 1,
      "maxAmountAbsolute": 1,
      "quantity": 1,
      "rateMinAbsolute": 0,
      "rateMin": 0,
      "rateDefault": 3.25,
      "rateMax": 4,
      "rateMaxAbsolute": 4,
      "productName": "Visa Qualified Credit",
      "productType": "NET_FEE",
      "isOverride": false,
      "override": false,
      "showoncart": false,
      "purchaseType": "P",
      "occurrence": {
        "type": "Transaction"
      },
      "groupName": "",
      "pricingTypeCategory": "ALL"
    },
    {
      "productId": "69002",
      "description": "Visa Qualified Credit",
      "feeMinAbsolute": 0,
      "feeMin": 0,
      "feeDefault": 0.15,
      "feeMax": 0,
      "feeMaxAbsolute": 0,
      "minAmountAbsolute": 0,
      "minAmt": 0,
      "defaultAmt": 0,
      "maxAmt": 1,
      "maxAmountAbsolute": 1,
      "quantity": 1,
      "rateMinAbsolute": 0,
      "rateMin": 0,
      "rateDefault": 3.15,
      "rateMax": 4,
      "rateMaxAbsolute": 4,
      "productName": "Visa Qualified Credit",
      "productType": "NET_FEE",
      "isOverride": false,
      "override": false,
      "showoncart": false,
      "purchaseType": "P",
      "occurrence": {
        "type": "Transaction"
      },
      "groupName": "",
      "pricingTypeCategory": "ALL"
    }
  ],
  "numberOfOutlets": 1,
  "merchantCreditInformation": {
    "bbbRating": "good",
    "complaints12Months": 0,
    "complaints36Months": 0,
    "OFACReviewPassed": "Y",
    "totalDocumentsNumber": 0
  },
  "siteSurvey": {
    "siteVisitation": "N",
    "onSiteVisitPerformed": "N",
    "productsandServicesSold": "OPTICAL"
  },
  "merchantTransactionInformation": {
    "mccTypes": "Business to Business (Supplies)",
    "mcc": "5812",
    "annualVolume": 10000,
    "averageTicket": 50,
    "highestTicket": 2,
    "category": "RETAIL",
    "amexMemberId": "12345767"
  },
  "merchantContactInformation": [
    {
      "contactType": "LOCATION",
      "state": "CA",
      "postalCode": "94041",
      "address1": "123 DO NOT SHIP",
      "email": "santhosh.rao.m@gmail.com",
      "url": "ENT.COM",
      "phone": "2435325432",
      "country": "USA",
      "city": "Mountain View"
    },
    {
      "contactType": "CORPORATE",
      "state": "CA",
      "postalCode": "94041",
      "address1": "123 DO NOT SHIP",
      "phone": "2435325432",
      "country": "USA",
      "city": "Mountain View",
      "email": "santhosh.rao.m@gmail.com",
      "url": "ENT.COM"
    },
    {
      "contactType": "TRADING",
      "state": "CA",
      "postalCode": "94041",
      "address1": "123 DO NOT SHIP",
      "phone": "2435325432",
      "country": "USA",
      "city": "Mountain View",
      "email": "santhosh.rao.m@gmail.com",
      "url": "ENT.COM"
    },
    {
      "contactType": "BILLING",
      "state": "CA",
      "postalCode": "94041",
      "address1": "123 OWNER ADDR",
      "address2": "TEST ST",
      "address3": "TEST ST",
      "phone": "2435325432",
      "country": "USA",
      "city": "Mountain View",
      "email": "santhosh.rao.m@gmail.com",
      "url": "ENT.COM"
    },
    {
      "contactType": "PRINCIPAL",
      "state": "MD",
      "postalCode": "21031",
      "address1": "11311 McCormick Road",
      "address2": "Suite 300",
      "address3": "TEST ST",
      "phone": "2435325432",
      "country": "USA",
      "city": "Hunt Valley",
      "email": "santhosh.rao.m@gmail.com",
      "url": "ENT.COM"
    }
  ],
  "merchantLocationInformation": [
    {
      "timeframeforDelivery": {
        "percentDelivered0Days": "0",
        "percentDelivered7Days": "0",
        "percentDelivered14Days": "0",
        "percentDelivered30Days": "10",
        "percentDeliveredMore30Days": "90"
      },
      "percentOfAnnualCardVolume": {
        "businessToBusiness": "0",
        "businessToConsumer": "100"
      },
      "percentageOfTotalAnnualVolume": {
        "businessToBusiness": "0",
        "businessToConsumer": "100"
      },
      "highestTicket": 56,
      "faceToFace": "100",
      "percentTransactionsOverPhoneorEmail": "0",
      "percentTransactionsOverInternet": "0",
      "stateOfIncorporation": "HI",
      "taxFilingName": "CUBA CIGAR 2",
      "istheBusinessaForeignEntity": "N",
      "tinRequestedGuid": "NA",
      "dbaName": "CUBA CIGAR 2",
      "legalName": "CUBA CIGAR 2",
      "employeeIdentificationNumber": "111223314",
      "yearsInBusiness": "2006-06-01",
      "yearsAtLocation": "2006-06-01",
      "organizationType": "Corporation",
      "obtained": "Y",
      "type": "Company Prepared Tax Returns",
      "endDate": "2017-03-01",
      "cash": "1000",
      "agentEmail": "santhosh.rao.m@gmail.com",
      "numberOfMonths": "12",
      "totalRevenue": "2000",
      "netIncome": "1000",
      "totalAssets": "2500",
      "totalLiabilities": "1500",
      "tangibleNetWorth": "2400",
      "workingCapital": "2300",
      "currentRation": "1.2",
      "debtToTNWRatio": "0.5",
      "country": "USA",
      "salesCurrency": [
        {
          "currency": "USD"
        }
      ],
      "pricingType": "01",
      "payeezyIndicator": "N",
      "visa": "Y",
      "mc": "N",
      "serviceLevel": "01",
      "tokenType": "01",
      "transArmorTokenType": "0001",
      "fundingCurrency": [
        {
          "currency": "USD"
        }
      ],
      "contactName": "contactName",
      "contractSignDate": "2018-01-01",
      "legalContactName": "legalCntactName",
      "irsSparkExclusion": "N",
      "yearIncorporated": "2000"
    }
  ],
  "bankInformation": [
    {
      "instName": "JPMORGAN CHASE BANK, NA",
      "abaNumber": "021000021",
      "accountNumber": "123",
      "accountType": "deposits"
    }
  ],
  "ownerInformation": [
    {
      "lastName": "Consumer",
      "firstName": "Jon",
      "nationalId": "111223314",
      "dateOfBirth": "1983-03-16",
      "title": "PARTNER",
      "percentageOwnership": 100,
      "isPrimary": "Y",
      "isCreditBureauReportAvailable": "Y",
      "bureauScore": "600",
      "governmentDocumentVerified": "Y",
      "gender": "M",
      "governmentDocument": "SSN CARD",
      "thirdPartyDatabaseVerified": "N",
      "thirdPartyDatabaseType": "a",
      "taxId": "111223314",
      "nationalIdType": "SSN"
    }
  ]

Thank You Page

At the end the merchant will be redirected to the Thank You page that will also display the Order ID.

Certify App

Certify your App to First Data

Now that we’ve successfully set up your app and taken a look at coding and deploying it to a production environment, it’s time to certify your app to First Data.

To certify an app, click the below link and enter your orderId (which you received by calling the POST Application/Checkout) endpoint.

First Data records your successful submissions to the sandbox environment to certify that your app is working properly. You will receive instructions for requesting Production access after a certain number of successful submissions to the sandbox environment.

To check your submission status during development, use our online Submission Result checker, where you can use your orderId to retrieve success/error information about the final submission. Click the link below to be redirected to the Submissions Results page.

  1. Certify App

Once you have your orderId, you’ll need to enter it in the form as shown below.

Certify App Example

If successful, then you’ll see something similar to the image displayed below and see a status of SUCCESS. Congratulations! Your are successfully certified with First Data!

Certify App Example

If your orderId results in an error, you’ll see something like the screenshot shown below and see a status of FAIL.

Certify App Example

In the event of an error, you’ll be able to click the Details button to view more information about the error. See the below screenshot for an example. You’ll need to resolve this error and attempt to submit again.

What if I encounter errors?

To proceed with the successful certification process, you will have to address the errors observed and repeat the submission attempt.

Certify App Example


Next Steps

In this section, we took a look at how to certify your system with First Data. As you can see, certification is a simple and straightforward process. In the next section, we’re going to finish up!

Next: Last step! Finish.

Finishing Up

Overview

Congratulations! You’ve made it to the end of this tutorial!

By now you should have a working understanding of how the Demo Marketplace app works. Please feel free to download the code from this repository and adjust it to suit your own application.

If you need any additional API-related information, please see our API Docs or return to the First Data Developer Center below.

  1. View the Marketplace API Docs
  2. Return to First Data Developer Center