Introducing Authorize.Net Accept.js

by Administrator Administrator on ‎06-29-2016 05:56 AM (55,814 Views)

Today we’re announcing the second module for the Authorize.Net Accept suite of tools: Authorize.Net Accept.js.

 

This new module makes it easier to integrate payments into applications while helping to reduce PCI DSS scope. With Accept.js, developers have control over the user experience without sending PCI data through their servers. One of the top-requested features in our developer community, Accept.js replaces Direct Post Method (DPM) with a modern implementation that doesn’t require a post-back. Accept.js can be used like any other payment type in the Authorize.Net API.

 

If you currently use the Authorize.Net API to process payment transactions, the integration should be the same, with only one additional step: before you POST the order/payment details to your server, you make a call to the Accept library and pass the resulting data to your server in place of any credit card details.

 

See our Sample Application on GitHub for a full working example.

 

Learn more about Accept.js by visiting the Authorize.Net Accept.js feature page.

Comments
by earthskater1
on ‎07-10-2016 11:29 AM

What does this error represent: E_WC_14:Accept.js encryption failed.

by xqm199090
on ‎07-18-2016 06:35 PM

I kept getting 'window[c] is not a function' error from 'Object.function.a.dispatchData.a.dispatchData [as dispatchData] (AcceptCore.js:1)'. Any Idea whats going on?

by pcmatt
on ‎07-18-2016 08:00 PM

I need a simple sample PHP file that can capture a payment form including email address to email the receipt via authorize.net account settings. 

 

The current sample incorporates all kinds of other functions that I don't need and the multiple php files and javascripts are difficult to understand.   Just one or two file/php page solution for simple process of payments is needed to REALLY replace the SIM and DPM API methods.

 

Please help!

 

-Matt

 

by bitforge
on ‎08-19-2016 10:13 AM

Is there going to be any official statement on where in the PCI SAQ spectrum this falls? It looks to me like it's SAQ-A EP, which is the same as DPM is, so in terms of compliance it's not really much of an improvement. Other processing providers are providing similar methods via JS that allow you to stay within the realm of SAQ-A, which is much, much easier to comply with...

by sirmann
on ‎08-19-2016 10:48 AM

bitforge, I agree with you on the PCI scope of this new inplementation.  This just does DPM a different way and doesn't change the SAQ level.  When I started reading this article, I got excited thinking we could use this method instead of SIM to maintain SAQ-A and not have to deal with iframing in the entire payment page and Auth.net posting the user back to our servers after the fact.  But after looking at the developer guide, it definitely stays SAQ-A EP because the payment input fields still originate from our code/servers.  I wish they would have spent a little more time and actually developed this JS method to create and host the payment input fields like most of the other major payment processors are doing to allow us to use it and maintain SAQ-A.

by treii28
on ‎08-19-2016 01:04 PM

Will this work somehow with the Customer Information Manager when a customer is creating a new payment profile or does it only work with direct transactions in the AIM/SIM?

by monis01
on ‎09-28-2016 11:58 PM

I am getting error 'window[b] is not a function' on integrating accept.js. what is this error?
using example from https://developer.authorize.net/api/reference/features/acceptjs.html

 

by firebird
on ‎12-31-2016 04:07 PM

I am also getting 'window[b] is not a function' - has anyone got Accept.js to work?  So far I've been immensely frustrated with the process...  With Stripe, I was up and accepting payments in an afternoon.

by firebird
on ‎01-04-2017 06:30 PM

I fixed my above-mentioned problem (window[b] is not a function) by making the response function a global function off of the window object:

 

window.submitPaymentData = function(res){...}

 

 

Now I have another question - is it possible to test card rejections using Accept.js?  I tried using the zip code 46282 as list here but the transaction is still approved.

by Administrator Administrator
on ‎03-07-2017 04:19 PM

Hi @firebird,

 

Just a heads up for you and anyone watching this thread that we've released code in sandbox that fixes many of the issues brought up here, and this code should make it into the production environment within the next couple of days.

 

Specifically for Accept.js, there's no longer any "Access-Control-Allow-Origin" related error in the console, the accept.js script can now be loaded at any point in the workflow, and the response handler function can be passed directly in the function call instead of having to pass the name of a global function.

 

Additionally, the zip code is making it through now where it wasn't before, so if you include the 46282 zip code in your nonce request, you should get back a nonce that will be declined when it's submitted in a payment request.

 

Of course, please let us know if anything's not working as expected!

by dcoho
‎03-26-2017 01:06 AM - edited ‎03-26-2017 01:09 AM

The example on https://developer.authorize.net/api/reference/features/acceptjs.html still does not work as it is for test environment (https://jstest.authorize.net/v1/Accept.js) with test credit card number 4111111111111111 expiry month 11 and expiry year 2017.  The responseHandler function is never called.

 

I am testing on local machine (localhost) with a self-signed certificate.  The entire code is inserted below:

 

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>Accept Sample App</title>
	<script type="text/javascript" src="https://jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>
	<script type="text/javascript">
		function sendPaymentDataToAnet() {
			var secureData = {}, authData = {}, cardData = {};
			
			cardData.cardNumber = document.getElementById('CARDNUMBER_ID').value;
			cardData.month = document.getElementById('EXPIRY_MONTH_ID').value;
			cardData.year = document.getElementById('EXPIRY_YEAR_ID').value;
			secureData.cardData = cardData;

			authData.clientKey  =  'my client key';
			authData.apiLoginID  =  'my login id';
			secureData.authData = authData;
			
			Accept.dispatchData(secureData, 'responseHandler');
		}
		
		function responseHandler(response) {
				if (response.messages.resultCode === 'Error') {
						for (var i = 0; i < response.messages.message.length; i++) {
								console.log(response.messages.message[i].code + ':' + response.messages.message[i].text);
						}
				} else {
						useOpaqueData(response.opaqueData)
				}
		}

		function useOpaqueData(responseData) {
				// This is where you would set the data descriptor & data value to be posted back to your server
				console.log(responseData.dataDescriptor);
				console.log(responseData.dataValue);
				alert(responseData.dataValue);
		}
	</script>
</head>
<body>
	<form name="form1" method="post">
		<p>
			Card Number:
			<input type="text" name="CARDNUMBER_ID" id="CARDNUMBER_ID"/>
		</p>
		<p>
			Expirty Month:
			<input type="text" name="EXPIRY_MONTH_ID" id="EXPIRY_MONTH_ID"/>
		</p>
		<p>
			Expiry Year:
			<input type="text" name="EXPIRY_YEAR_ID" id="EXPIRY_YEAR_ID"/>
		</p>
		<button type="submit" onclick="sendPaymentDataToAnet()">Pay</button>	
	</form>
</body>
</html>

 

by Administrator Administrator
‎03-26-2017 11:36 AM - edited ‎03-26-2017 11:37 AM

We're waiting for the next version of that page to go live. That next version shows a better example of putting the responseHandler function right within the sendPaymentDataToAnet function.

 

However, the example of specifying the name of a global function (as is currently in the doc) should still work. The reason it's not working for you is that the browser is refreshing the page when you click the "Pay" button, because it's trying to submit the form to the current URL. That's because in our example, we say:

<button type="submit" onclick="sendPaymentDataToAnet()">Pay</button>

 

When we should be saying:

<button type="button" onclick="sendPaymentDataToAnet()">Pay</button>

 

Because the button in your code is a "submit" button, the browser is actually trying to do a post. All you want to do is for the button to kick off the function. That's another fix for that bad code sample in the next version of this page whenever it goes live.

 

 

Here's a whole sample page that might be helpful:

<!DOCTYPE html>
<html>
<head>
<title>Payment Form</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" >


<script type="text/javascript" src="https://jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/jquery-2.1.4.min.js" charset="utf-8"></script>
    
</head>

<body>

<h1>Payment Form</h1>
    
    
<form id="paymentForm">
    Card Number<br>
    <input type="tel" class="form-control" id="CARDNUMBER_ID" placeholder="5424000000000015" value="5424000000000015" autocomplete="off" /><br><br>
    Expiration Date (Month)<br>
    <input type="text" class="form-control" id="EXPIRY_MONTH_ID" placeholder="12" value="12" /><br><br>
    Expiration Date (Year)<br>
    <input type="text" class="form-control" id="EXPIRY_YEAR_ID" placeholder="2020" value="2020" /><br><br>
    Card Security Code<br>
    <input type="text" class="form-control" id="CARD_CODE" placeholder="900" value="900" /><br><br>
    Amount<br>
    <input type="text" class="form-control" id="AMOUNT" placeholder="10.00" value="10.00" /><br><br>
    ZIP<br>
    <input type="text" class="form-control" id="ZIP" placeholder="46282" value="" /><br><br>
    <button type="button" class="Button" id="submitButton" onclick="sendPaymentDataToAnet()">Pay</button>
</form>

<script type="text/javascript">
    
    
// Upon clicking the "Pay" button, extract the card number and expiration date, and pass those to Accept.js for submission to Authorize.Net
function sendPaymentDataToAnet() {
var secureData = {}; authData = {}; cardData = {}; cardData.cardNumber = document.getElementById("CARDNUMBER_ID").value; cardData.month = document.getElementById("EXPIRY_MONTH_ID").value; cardData.year = document.getElementById("EXPIRY_YEAR_ID").value; cardData.cardCode = document.getElementById("CARD_CODE").value; cardData.zip = document.getElementById("ZIP").value; secureData.cardData = cardData; // The Authorize.Net Client Key is used in place of the traditional Transaction Key. The Transaction Key is a shared secret and must never be exposed. The Client Key is a public Key suitable for use where someone outside the merchant might see it. authData.clientKey = "Client Key"; authData.apiLoginID = "Login ID"; secureData.authData = authData; Accept.dispatchData(secureData, responseHandler); // When the response is returned from Accept.js, validate that the data looks correct, and record the OpaqueData to the console, and call the transaction processing function. function responseHandler(response) { if (response.messages.resultCode === "Error") { for (var i = 0; i < response.messages.message.length; i++) { console.log(response.messages.message[i].code + ": " + response.messages.message[i].text); } alert("accept.JS library error!") } else { console.log(response.opaqueData.dataDescriptor); console.log(response.opaqueData.dataValue); callTransactionProcessor(response.opaqueData); } } } // Using query.js, do an AJAX call to a separate URL on the site to do the actual transaction processing. function callTransactionProcessor(responseData) { $.ajax({ url: "https://your site/Path to Some Payment Processor Script", data: {amount: document.getElementById("AMOUNT").value, dataDesc: responseData.dataDescriptor, dataValue: responseData.dataValue}, method: "POST", timeout: 5000 }).done(function(data){ console.log("Success"); }).fail(function(){ console.log("Error"); }).always(function(textStatus){ console.log(textStatus); messageFunc(textStatus); }) } // The result of the transaction processing will be returned from the processing script as a JSON object. Parse the object to determine success or failure, and alert the user. function messageFunc(returnMsg) { try{ responseObj=JSON.parse(returnMsg); if(responseObj.transactionResponse.responseCode=="1"){ message="Transaction Successful! - Transaction ID: "+responseObj.transactionResponse.transId; } else{ message="Transaction Failed"; if(responseObj.transactionResponse.errors!=null) { message+=responseObj.transactionResponse.errors.error.errorText; } if(responseObj.transactionResponse.transId!=null) { message+=(" - Transaction ID: "+responseObj.transactionResponse.transId) } } } catch(error){ console.log("Couldn't parse result string"); message="Error."; } alert(message); } </script> </body> </html>