| [ Web Proxy ] |
| Viewing: https://docs.nmi.com/docs/../docs/quick-start-tutorial | [Back] [Original] |
Accept payments online in four easy steps
This documentation is intended for existing Collect.js integrations. For new integrations, use the Payment Component with the NMI REST API. If you're migrating from Collect.js, follow the Classic API migration playbook.
This quick setup guide will get Collect.js running on your site in minutes. See our advanced integrations for solution customization options.
Collect.js authenticates with a public API key that can only be used to generate payment tokens. Create this in the Merchant Portal under Settings > Security Keys.
Collect.js is loaded from the gateway with the following in your page header.
<script
src="https://secure.nmi.com/token/Collect.js"
data-tokenization-key="USER.PUBLICAPIKEY"
data-variant="inline"
></script>Details on implementing Apple Pay, Google Pay, and e-check further down this page, but let's start with the basic credit card fields.
Collect.js is looking for specific "id" values on the page to embed its iframes, as well as what button submits the form. These ids can be anything you want, but this example uses the defaults.
<form action="pay.php" type="POST">
<div id="ccnumber"></div>
<div id="ccexp"></div>
<div id="cvv"></div>
<input id="payButton" type="submit" value="Submit Payment">
</form>On page load, these divs will each have an iframe embedded as a child element. These iframes are hosted by the gateway and each will contain a single input element. These inputs will be unstyled by default. Clickhereto see how to customize their CSS. The submit button will maintain your styling and will not have an iframe added, the id simply tells Collect.js what button submits the form relevant to the payment token. When submitted, the payment_token variable and value are automatically added to the form submission, and a JS callback (listed at the bottom of this page) is returned to your application with some more data.
Additional SolutionsLightbox offers an alternative pop-up style display for an even easier integration.
Gateway.js allows you to add additional gateway services, such as Payer Authentication (3D Secure) and Kount (Advanced Fraud Prevention) to your implementation.
When the user fills out the embedded fields and submits the form, Collect.js will automatically add the payment_token variable and token value to the form submission, which in this case is being sent to the site's /pay.php endpoint. From there your server should create the full Payment API request for what action you're performing, including the payment_token.
TipFor a smoother user experience, disable form submission until you have confirmed that the payment fields are successfully stored, as well as any other pre-transaction checks you perform.
That's it, your server will get a response from the Payment API with the result of your request, and the payment token will be destroyed since it has been used.
If you intend to use CSP with Collect.js, you need to add the following rules to ensure the payment system functions properly without CSP violations.
Minimum CSP Header:
<meta http-equiv="Content-Security-Policy" content="
script-src 'self' https://secure.nmi.com https://applepay.cdn-apple.com https://pay.google.com 'nonce-{YOUR_UNIQUE_NONCE}';
style-src 'self' https://secure.nmi.com 'nonce-{YOUR_UNIQUE_NONCE}';
connect-src 'self' https://secure.nmi.com https://pay.google.com;
frame-src https://secure.nmi.com https://pay.google.com;
form-action 'self';
">Complete Strict CSP Header (Recommended):
<meta http-equiv="Content-Security-Policy" content="
default-src 'none';
script-src 'self' https://secure.nmi.com https://applepay.cdn-apple.com https://pay.google.com 'nonce-{YOUR_UNIQUE_NONCE}';
style-src 'self' https://secure.nmi.com 'nonce-{YOUR_UNIQUE_NONCE}';
connect-src 'self' https://secure.nmi.com https://pay.google.com;
frame-src https://secure.nmi.com https://pay.google.com;
img-src 'self' data: https://secure.nmi.com;
base-uri 'none';
form-action 'self';
object-src 'none';
">Essential domains for script-src:
https://secure.nmi.com - Primary NMI/Collect.js domainhttps://applepay.cdn-apple.com - Apple Pay functionalityhttps://pay.google.com - Google Pay functionality'nonce-{YOUR_UNIQUE_NONCE}' - Your page-specific nonceEssential domains for connect-src and frame-src:
https://secure.nmi.com - Payment API communication and iframeshttps://pay.google.com - Google Pay API calls and iframes1. Nonce Generation: Generate a unique, cryptographically secure nonce for each page load:
$nonce = base64_encode(random_bytes(16));2. Apply Nonces to Inline Content:
<script> tags with inline code need nonce="{YOUR_NONCE}"<style> tags with inline CSS need nonce="{YOUR_NONCE}"3. CSP-Compliant Script Loading:
<!-- Load Collect.js -->
<script src="https://secure.nmi.com/token/Collect.js"
data-tokenization-key="YOUR_PUBLIC_KEY_HERE"
></script>
<!-- Your payment configuration -->
<script nonce="{YOUR_UNIQUE_NONCE}">
document.addEventListener("DOMContentLoaded", function () {
CollectJS.configure({
// Your configuration here
});
});
</script>
<!-- Your page styles -->
<style nonce="{YOUR_UNIQUE_NONCE}">
/* Your CSS here */
</style>If you specify a custom callback like validationCallback in CollectJS.configure() , it normally requires access to the JavaScript eval method to execute the callback. Most strict CSP rules do not allow for unsafe-eval which will block this. If you add "blockEval": "true" to the payload of CollectJS.configure() it will support a restricted form of custom callback without using eval. The callback must be a method that exists in the code, and is called by name, rather than being a free-standing code block. In this example, myCallback will be called when a validation has completed, and log the status to the console.
<script nonce="{YOUR_UNIQUE_NONCE}">
document.addEventListener("DOMContentLoaded", function () {
CollectJS.configure({
"blockEval": "true",
// ...
"validationCallback": "myCallback"
});
});
function myCallback(field, status, message) {
if (status) {
var logText = field + " is now OK: " + message;
} else {
var logText = field + " is now Invalid: " + message;
}
console.log("myCallback called: " + logText);
}
</script>The following is a PCI compliant functioning Collect.js integration using Apple Pay/Google Pay custom CSS, product info, and uses callbacks to perform actions when specific events (like all payment fields pass validation)
Use the below sample to see a barebones integration in action.
<html>
<head>
<!-- This sets a PCI compliance CSP -->
<!-- The nonce must be securely generated by your hosting page per page-load -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'none';
script-src 'self' https://secure.nmi.com https://applepay.cdn-apple.com 'nonce-abc123';
style-src 'self' https://secure.nmi.com 'nonce-abc123';
connect-src https://secure.nmi.com;
frame-src https://secure.nmi.com;
base-uri 'none';
form-action 'self';
">
<!-- This loads Collect.js from the server -->
<script src="https://secure.nmi.com/token/Collect.js"
data-tokenization-key="W7a2Z7-GuwUy8-AK4G68-MKAEFv"
></script>
</head>
<body>
<h1>Payment Component Sample</h1>
<!-- Create a form that will submit all customer data as well
as the Collect.js payment token to another page on your
server -->
<form action="/your-page.php" method="POST">
<!-- Normally not a visible input to the user, but here
for easy testing -->
<div class="input">
<span>Amount</span>
<input type="text" name="amount" value="10.00" />
</div>
<!-- Customer name, email, and postal code for AVS verification -->
<div class="input">
<span>First Name</span>
<input type="text" name="firstname" value="Example" />
</div>
<div class="input">
<span>Last Name</span>
<input type="text" name="lastname" value="User" />
</div>
<div class="input">
<span>Email Address</span>
<input type="text" name="email" value="[email protected]" />
</div>
<div class="input">
<span>Postal Code</span>
<input type="text" name="zip" value="12345" />
</div>
<!-- Credit card fields -->
<div class="input">
<span>Card Number</span>
<div id="demoCcnumber"></div>
</div>
<div class="input">
<span>Expiration Date</span>
<div id="demoCcexp"></div>
</div>
<div class="input">
<span>CVV</span>
<div id="demoCvv"></div>
</div>
<!-- Submit the form to your server -->
<button id="demoPayButton" type="button">Pay</button>
</form>
<!-- The nonce must be securely generated by your hosting page per page-load -->
<script nonce="abc123">
// This will load Collect.js and render text fields
// on page load, but you can call "CollectJS.configure"
// whenever you want to load the payment form fields
document.addEventListener("DOMContentLoaded", function () {
CollectJS.configure({
paymentSelector: "#demoPayButton",
variant: "inline",
invalidCss: {
color: "#e74c3c",
"border-color": "#e74c3c",
},
validCss: {
color: "black",
"border-color": "#2ecc71",
},
placeholderCss: {
color: "darkgray",
"background-color": "#ffffff",
},
focusCss: {
color: "black",
"border-color": "#4681f4",
},
fields: {
ccnumber: {
selector: "#demoCcnumber",
title: "Card Number",
placeholder: "0000 0000 0000 0000",
},
ccexp: {
selector: "#demoCcexp",
title: "Card Expiration",
placeholder: "00 / 00",
},
cvv: {
display: "show",
selector: "#demoCvv",
title: "CVV Code",
placeholder: "123",
}
},
price: "1.00",
currency: "USD",
country: "US",
validationCallback: function (field, status, message) {
if (status) {
var message = field + " is now OK: " + message;
} else {
var message = field + " is now Invalid: " + message;
}
console.log(message);
},
timeoutDuration: 10000,
timeoutCallback: function () {
console.log(
"The tokenization didn't respond in the expected timeframe. This could be due to an invalid or incomplete field or poor connectivity"
);
},
fieldsAvailableCallback: function () {
console.log("Collect.js loaded the fields onto the form");
},
callback: function (response) {
alert(response.token);
var input = document.createElement("input");
input.type = "hidden";
input.name = "payment_token";
input.value = response.token;
var form = document.getElementsByTagName("form")[0];
form.appendChild(input);
form.submit();
},
});
});
</script>
<style nonce="abc123">
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
max-width: 400px;
margin: 0 auto;
padding: 15px;
background-color: #f5f5f5;
color: #333;
font-size: 14px;
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 20px;
font-weight: 300;
font-size: 24px;
}
form {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.input {
margin-bottom: 15px;
}
.input span {
display: block;
margin-bottom: 4px;
font-weight: 500;
color: #555;
font-size: 13px;
}
.input input {
width: 100%;
padding: 8px;
border: 1px solid #e1e1e1;
border-radius: 8px;
font-size: 14px;
box-sizing: border-box;
transition: border-color 0.3s ease;
}
.input input:focus {
outline: none;
border-color: #4681f4;
}
#demoPayButton {
width: 100%;
padding: 12px;
background-color: #4681f4;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
margin-top: 15px;
transition: background-color 0.3s ease;
}
#demoPayButton:hover {
background-color: #3f73dd;
}
#demoPayButton:active {
transform: translateY(1px);
}
</style>
</body>
</html>When the payment form is submitted, your application will get a callback with some data about the collected payment information. Here's an example of a debit card being keyed in. The check info would be filled out for ACH payments, and the wallet section would be populated for Apple Pay and Google Pay transactions.
{
"tokenType": "inline",
"token": "8kR4TfnC-gU5ZpZ-2jWgJ9-536t4AMnVUzj",
"initiatedBy": {
"isTrusted": true
},
"card": {
"number": "411111******1111",
"bin": "411111",
"exp": "1025",
"type": "visa",
"category": "debit",
"hash": ""
},
"check": {
"name": null,
"account": null,
"aba": null,
"transit": null,
"institution": null,
"hash": null
},
"wallet": {
"cardDetails": null,
"cardNetwork": null,
"email": null,
"billingInfo": {
"address1": null,
"address2": null,
"firstName": null,
"lastName": null,
"postalCode": null,
"city": null,
"state": null,
"country": null,
"phone": null
},
"shippingInfo": {
"method": null,
"address1": null,
"address2": null,
"firstName": null,
"lastName": null,
"postalCode": null,
"city": null,
"state": null,
"country": null,
"phone": null
}
}
}Updated 23 days ago
| Web Proxy Viewer | New URL | Original Page |