Integration and Testing

Authorize.Net API questions and help with your payment integration.

Reply
Member
Posts: 1
Registered: ‎09-28-2021

no action=transactResponse in Accept Hosted iframe for Authorize.net

I'm trying to implement the Authorize.net Accept Hosted hosted checkout solution in a Coldfusion application.

 

(For all the ColdFusion developers, this code run on BlueDragon.NET 9 which a CF9 implementation. The cfscript stacktrace support is terrible which is why this code is in tags and not in cfscript.)

 

Using our sandbox authorize.net account, the iframe hosted checkout page shows up. I can fill out the credit card info and submit. I get the receipt, 2 receipt emails from authorize.net and get sent to the confirmation page, but the case "transactResponse" in AuthorizeNetIFrame.onReceiveCommunication never gets triggered. I put a alert in the javascript function to see all the querystrings that come into the iframe.

 

Other than the coldfusion code to authenticate and get the token (which seems to work) I got the rest of the code from the Authorize.net documentation.

 

Any idea why I don't see the action=transactResponse query string come into iframe with the response from the authorize.net credit card transaction.

 

I tried this with a live authorize.net account as well and I get a 'User authentication failed due to invalid authentication values.' on the iframe payment page even though I can authenticate and get a token for the iframe successfully. What am I missing. Any help would be appreciated.

 

Sensitive parts of the code (i.e. credentials), email, and address have been redacted.


Here's the code for the page with the iframe:

 

<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<head>
	<title>HostedPayment Test Page</title>
	<script src="https://code.jquery.com/jquery-3.6.0.js"
			integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
			crossorigin="anonymous"></script>
	<script type="text/javascript">

		$(function () {

			$("#btnOpenAuthorizeNetIFrame").click(function () {
				$("#add_payment").show();
				$("#send_token").attr({ "action": "https://test.authorize.net/payment/payment", "target": "add_payment" }).submit();
				$(window).scrollTop($('#add_payment').offset().top - 50);
			});

		});


</script>
</head>
<body>

<cfif NOT IsDefined("url.CFID") or NOT IsDefined("url.CFTOKEN")>
	<p style="color: red;">Error: CFID and CFTOKEN required as URL parameters...</p>
	<cfabort />
</cfif>

<cfinclude template="../#client.custom_path#/constants.cfm" />

<cfset variables.LOGIN_TOKEN_URL = "https://apitest.authorize.net/xml/v1/request.api" />
<cfset variables.API_LOGIN_ID = "ZZZZZZZZZZZ" />
<cfset variables.TRANSACTION_KEY = "ZZZZZZZZZZZZZZ" />

<h2>Authenticate</h2>

<cfoutput>
<cfsavecontent variable="variables.soapBody">
<authenticateTestRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
    <merchantAuthentication>
        <name>#variables.API_LOGIN_ID#</name>
        <transactionKey>#variables.TRANSACTION_KEY#</transactionKey>
    </merchantAuthentication>
</authenticateTestRequest>
</cfsavecontent>
</cfoutput>

<cfhttp url="#variables.LOGIN_TOKEN_URL#"
	method="post"
	result="variables.result1">
	<cfhttpparam
		type="xml"
		value="#Trim( variables.soapBody )#"
		/>
</cfhttp>

<cfdump var="#variables.result1#" />

<cfset variables.response1 = XMLParse(Trim(Right(variables.result1.filecontent, Len(variables.result1.filecontent)-1))) />
<cfset variables.response = StructNew() />

<cfset variables.response.resultCode = xmlSearch(Trim(Right(variables.result1.filecontent, Len(variables.result1.filecontent)-1)),
	"//*[ local-name() = 'resultCode' ]"
	) />
<cfif IsDefined("variables.response.resultCode[1].XmlText")>
	<cfset variables.response.resultCode = variables.response.resultCode[1].XmlText />
</cfif>

<cfset variables.response.code = xmlSearch(Trim(Right(variables.result1.filecontent, Len(variables.result1.filecontent)-1)),
	"//*[ local-name() = 'code' ]"
	) />
<cfif IsDefined("variables.response.code[1].XmlText")>
	<cfset variables.response.code = variables.response.code[1].XmlText />
</cfif>

<cfset variables.response.text = xmlSearch(Trim(Right(variables.result1.filecontent, Len(variables.result1.filecontent)-1)),
	"//*[ local-name() = 'text' ]"
	) />
<cfif IsDefined("variables.response.text[1].XmlText")>
	<cfset variables.response.text = variables.response.text[1].XmlText />
</cfif>

<cfif IsDefined("variables.response.text") AND FindNoCase("Successful", variables.response.text)>
	<p style="color: green; font-weight: bold;">Success</p>
<cfelse>
	<p style="color: red; font-weight: bold;">Failure</p>
</cfif>

<cfdump var="#variables.response#" />
<cfdump var="#variables.response1#" />

<h2>Get token</h2>

<cfoutput>
<cfsavecontent variable="variables.soapBody2">
<getHostedPaymentPageRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
  <merchantAuthentication>
    <name>#variables.API_LOGIN_ID#</name>
    <transactionKey>#variables.TRANSACTION_KEY#</transactionKey>
  </merchantAuthentication>
  <transactionRequest>
    <transactionType>authCaptureTransaction</transactionType>
    <amount>0.01</amount>
    <customer>
      <email>ZZZZZZZZ@ZZZZZZZZ.com</email>
    </customer>
    <billTo>
        <firstName>ZZZZZZZZ</firstName>
        <lastName>Tester1</lastName>
        <company></company>
        <address>123 Main Street</address>
        <city>ZZZZZZZZ</city>
        <state>ZZ</state>
        <zip>22222</zip>
        <country>US</country>
    </billTo>
  </transactionRequest>
  <hostedPaymentSettings>
    <setting>
      <settingName>hostedPaymentReturnOptions</settingName>
      <settingValue>{"showReceipt": true, "url": "https://ZZZZZZZZ.com/test/hosted_pages/cart_hosted_confirm.cfm", "urlText": "Continue", "cancelUrl": "https://ZZZZZZZZ.com/test/hosted_pages/cart_hosted_cancel.cfm", "cancelUrlText": "Cancel"}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentButtonOptions</settingName>
      <settingValue>{"text": "Pay"}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentStyleOptions</settingName>
      <settingValue>{"bgColor": "blue"}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentPaymentOptions</settingName>
      <settingValue>{"cardCodeRequired": true, "showCreditCard": true, "showBankAccount": false}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentSecurityOptions</settingName>
      <settingValue>{"captcha": false}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentShippingAddressOptions</settingName>
      <settingValue>{"show": false, "required": false}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentBillingAddressOptions</settingName>
      <settingValue>{"show": true, "required":true}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentCustomerOptions</settingName>
      <settingValue>{"showEmail": true, "requiredEmail": true, "addPaymentProfile": false}</settingValue>
    </setting>
    <setting>
      <settingName>hostedPaymentOrderOptions</settingName>
      <settingValue>{"show": true, "merchantName": "Test Company, LLC"}</settingValue>
    </setting>
	<setting>
      <settingName>hostedPaymentIFrameCommunicatorUrl</settingName>
      <settingValue>{"url": "https://ZZZZZZZZ.com/test/hosted_pages/IFrameCommunicator.html"}</settingValue>
    </setting>
  </hostedPaymentSettings>
</getHostedPaymentPageRequest>
</cfsavecontent>
</cfoutput>

<cfhttp url="#variables.LOGIN_TOKEN_URL#"
	method="post"
	result="variables.result2">
	<cfhttpparam
		type="xml"
		value="#Trim( variables.soapBody2 )#"
		/>
</cfhttp>

<cfdump var="#variables.result2#" />

<cfset variables.response2 = XMLParse(Trim(Right(variables.result2.filecontent, Len(variables.result2.filecontent)-1))) />
<cfset variables.responseToken = StructNew() />

<cfset variables.responseToken.resultCode = xmlSearch(Trim(Right(variables.result2.filecontent, Len(variables.result2.filecontent)-1)),
	"//*[ local-name() = 'resultCode' ]"
	) />
<cfif IsDefined("variables.responseToken.resultCode[1].XmlText")>
	<cfset variables.responseToken.resultCode = variables.responseToken.resultCode[1].XmlText />
</cfif>

<cfset variables.responseToken.code = xmlSearch(Trim(Right(variables.result2.filecontent, Len(variables.result2.filecontent)-1)),
	"//*[ local-name() = 'code' ]"
	) />
<cfif IsDefined("variables.responseToken.code[1].XmlText")>
	<cfset variables.responseToken.code = variables.responseToken.code[1].XmlText />
</cfif>

<cfset variables.responseToken.text = xmlSearch(Trim(Right(variables.result2.filecontent, Len(variables.result2.filecontent)-1)),
	"//*[ local-name() = 'text' ]"
	) />
<cfif IsDefined("variables.responseToken.text[1].XmlText")>
	<cfset variables.responseToken.text = variables.responseToken.text[1].XmlText />
</cfif>

<cfif IsDefined("variables.responseToken.text") AND FindNoCase("Successful", variables.responseToken.text)>
	<p style="color: green; font-weight: bold;">Success</p>
	
	<cfset variables.responseToken.token = xmlSearch(Trim(Right(variables.result2.filecontent, Len(variables.result2.filecontent)-1)),
	"//*[ local-name() = 'token' ]"
	) />
	<cfif IsDefined("variables.responseToken.token[1].XmlText")>
		<cfset variables.responseToken.token = variables.responseToken.token[1].XmlText />
	</cfif>
<cfelse>
	<p style="color: red; font-weight: bold;">Failure</p>
</cfif>

<cfdump var="#variables.response2#" />
<cfdump var="#variables.responseToken#" />

<h2>Hosted Page</h2>
<cfif IsDefined("variables.responseToken.token") AND Len(Trim(variables.responseToken.token)) GT 0>

	<div>
	Open Authorize.net in an iframe to complete transaction
	<button id="btnOpenAuthorizeNetIFrame" onclick="">Show Payment Form</button>
	</div>
	<div id="iframe_holder" class="center-block" style="width:90%;max-width: 1000px">
	<iframe id="add_payment" class="embed-responsive-item panel" name="add_payment" width="100%"  frameborder="0" scrolling="no" hidden="true">
	</iframe>
	</div>
	<cfoutput>
	<form id="send_token" action="" method="post" target="add_payment">
	<input type="hidden" name="token" value="#variables.responseToken.token#" />
	</form>	
	</cfoutput>
	
	<script type="text/javascript">
		(function () {
			if (!window.AuthorizeNetIFrame) window.AuthorizeNetIFrame = {};
				AuthorizeNetIFrame.onReceiveCommunication = function (querystr) {
				
					alert('processing 1:'+querystr);
					
					var params = parseQueryString(querystr);
						switch (params["action"]) {
							case "successfulSave":
								break;
							case "cancel":
								break;
							case "resizeWindow":
								var w = parseInt(params["width"]);
								var h = parseInt(params["height"]);
								var ifrm = document.getElementById("add_payment");
								ifrm.style.width = w.toString() + "px";
								ifrm.style.height = h.toString() + "px";
								break;
							case "transactResponse":
								var ifrm = document.getElementById("add_payment");
								ifrm.style.display = 'none';
								
								var formData = { gatewayResponse: params["response"] };
								$.ajax({
									url: "cart_hosted_async_log.cfm?<cfoutput>#URLTOKEN#</cfoutput>",
									type: "POST",
									data: formData,
									success: function(data, textStatus, jqXHR)
									{},
									error: function (jqXHR, textStatus, errorThrown)
									{}
								});
								break;
							}
					};

				function parseQueryString(str) {
					var vars = [];
					var arr = str.split('&');
					var pair;
					for (var i = 0; i < arr.length; i++) {
						pair = arr[i].split('=');
						vars.push(pair[0]);
						vars[pair[0]] = unescape(pair[1]);
						}
					return vars;
					}
		}());
	</script>
</cfif>

</body>
</html>

Here's the code for the IFrameCommunicator.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Iframe Communicator</title>
	<script type="text/javascript">
		//<![CDATA[
			function callParentFunction(str) {
				if (str && str.length > 0 
					&& window.parent 
					&& window.parent.parent
					&& window.parent.parent.AuthorizeNetIFrame 
					&& window.parent.parent.AuthorizeNetIFrame.onReceiveCommunication)
					{
// Errors indicate a mismatch in domain between the page containing the iframe and this page.
						window.parent.parent.AuthorizeNetIFrame.onReceiveCommunication(str);
					}
				}

			function receiveMessage(event) {
				if (event && event.data) {
					callParentFunction(event.data);
					}
				}

				if (window.addEventListener) {
					window.addEventListener("message", receiveMessage, false);
					} else if (window.attachEvent) {
						window.attachEvent("onmessage", receiveMessage);
					}

				if (window.location.hash && window.location.hash.length > 1) {
					callParentFunction(window.location.hash.substring(1));
					}
		//]]/>
	</script>
</head>
<body>
</body>
</html>

 

Member
Posts: 11
Registered: ‎09-28-2021

Re: no action=transactResponse in Accept Hosted iframe for Authorize.net

Thanks for taking the time to discuss that, I'd love to learn more about this area. Would you mind updating your blog post with additional insights? It will be really helpful for all of us.

flip coin