cancel
Showing results for 
Search instead for 
Did you mean: 

Error 99 - Fingerprint is correct - Help!

I have been troubleshooting this issue for an entire day now, and I simply cannot figure out what the problem is. I am trying to call the SIM API, and I initially was getting error 97 because my timestamp was incorrectly formatted. After fixing that and a few other issues, I've started getting the Error 99 response. I have used the Error 99 troubleshooter to generate the expected fingerprint based on my information, and it appears to be identical to the fingerprint that I am sending. I have confirmed my transaction id, and I have attempted to submit the amount as both 10.00 and 1000. I've also hardcoded the timestamp just to confirm that there is no issue with generating the fingerprint at a slightly different moment in time.

 

I'm at my wits end on what could be wrong and I'd appreciate any assistance you could provide. I'm using VisualForce pages and APEX code through Force.com, so I've had to custom code everything based on the Java examples.

pinonium
Member
1 ACCEPTED SOLUTION

Accepted Solutions

Wait a minute is that a ) at the end of your x_fp_hash value field.

<INPUT TYPE='text' NAME='x_fp_hash' VALUE='{!fingerprint})' />

 

Try this instead of posting to

https://test.authorize.net/gateway/transact.dll

Post to

https://developer.authorize.net/tools/paramdump/index.php

 

http://developer.authorize.net/tools/datavalidation/

So you can see exactly what you are sending to authorize.net. And view the page source on it and see if there is any white-space on any of the hash key value.

View solution in original post

10 REPLIES 10

Paste your source code. Also view source on your page and paste the HTML (put in **** for your login ID and transaction key). Use code boxes, fourth option from the left in Rich Text mode.

TJPride
Expert

 

The first VisualForce page with a form for inserting Credit Card

<apex:page controller="CreditCardController">
  <FORM NAME="secure_redirect_form" ID="secure_redirect_form_id" ACTION="https://test.authorize.net/gateway/transact.dll" METHOD="GET">

  <label>CreditCardNumber</label><input value='370000000000002' type='text' class='text' name='x_card_num' size='15'>
    </input>
  <label>Exp.</label><input value='12/15' type='text' class='text' name='x_exp_date' size='4'></input>
  <label>Amount</label><input type='text' class='text' name='x_amount' size='9'
    readonly='true' value='{!amount}'></input>
  <INPUT TYPE='HIDDEN' NAME='x_first_name' VALUE='test' />
  <INPUT TYPE='HIDDEN' NAME='x_last_name' VALUE='test2' />
  <INPUT TYPE='HIDDEN' NAME='x_card_type' VALUE='A' />
  <INPUT TYPE='HIDDEN' NAME='x_card_code' VALUE='4221' />
  <INPUT TYPE='HIDDEN' NAME='x_invoice_num' VALUE='67897654' />
  <INPUT TYPE='HIDDEN' NAME='x_relay_url' VALUE='{!relayResponseUrl}' />
  <INPUT TYPE='HIDDEN' NAME='x_login' VALUE='{!apiLoginId}' />
  <INPUT TYPE='HIDDEN' NAME='x_fp_sequence' VALUE='{!sequence}' />
  <INPUT TYPE='text' NAME='x_fp_timestamp' VALUE='{!timestamp}' />
  <INPUT TYPE='text' NAME='x_fp_hash' VALUE='{!fingerprint})' />
  <INPUT TYPE='HIDDEN' NAME='x_version' VALUE='3.1' />
  <INPUT TYPE='HIDDEN' NAME='x_method' VALUE='CC' />
  <INPUT TYPE='HIDDEN' NAME='x_type' VALUE='AUTH_CAPTURE' />
  <INPUT TYPE='HIDDEN' NAME='x_market_type' VALUE='2' />
  <INPUT TYPE='HIDDEN' NAME='x_test_request' VALUE='FALSE' />
  <INPUT TYPE='HIDDEN' NAME='notes' VALUE='extra hot please' />
  <INPUT TYPE='SUBMIT' NAME='buy_button' VALUE='BUY' />
  <INPUT TYPE='HIDDEN' NAME='x_cpversion' VALUE='1.0' />
  <INPUT TYPE='HIDDEN' NAME='x_device_type' VALUE='5'/>
  <INPUT TYPE='HIDDEN' NAME='x_tran_key' VALUE='{!transactionKey}' />
</form>

</apex:page>

 

The controller in APEX

public with sharing class CreditCardController {

    public String input { get; set; }
    public long timestamp = doTime();
    public String sequence = '111';
    public String apiLoginId = '**********';
    public String transactionKey = '****************';
    public String receiptPageUrl = 'http://MERCHANT_HOST/order_receipt.jsp';
    public String MD5HashKey = apiLoginId;
    public String amount = '10.00';
    public String fingerprint = doCrypto();

    public String getFingerprint() {
        return fingerprint;
    }
    public String getTransactionKey() {
        return transactionKey;
    }
    public String getInput() {
        input = 'seven';
        return input;
    }
    public long getTimestamp() {
        return timestamp;
    }
    public String getSequence() {
        return sequence;
    }
    public String getApiLoginId() {
        return apiLoginId;
    }
    public String getRelayResponseUrl() {
        return 'https://c.na14.visual.force.com/apex/CreditCardReturn';
    }
    public String getAmount() {
        return '10.00';
    }
    
    public long doTime(){
        long timestamp = System.currentTimeMillis() / 1000;
        return timestamp;
    }
    
    public String doCrypto(){
        String inputStr = apiLoginId + '^' + sequence + '^' + timestamp + '^' + amount + '^';
        
        String algorithmName = 'hmacMD5';
        Blob mac = Crypto.generateMac(algorithmName,  Blob.valueOf( inputStr ), 
                                                      Blob.valueOf( transactionKey ));
        
        //Convert from Blob to hexadecimal format String
        String fingerprint = EncodingUtil.convertToHex( mac );
        return fingerprint;
    }
}

 

When I've been testing this, I've attempted to replace timestamp with a hard value. However, for clarity, I've gone ahead and replace with the timestamp variable. Please let me know if there is any additional information needed.

 

 

Response from a.net

response><ResponseCode>3</ResponseCode><Errors><Error><ErrorCode>99</ErrorCode><ErrorText>This transaction cannot be accepted.</ErrorText></Error></Errors><AuthCode></AuthCode><AVSResultCode>P</AVSResultCode><CVVResultCode/><TransID>0</TransID><RefTransID/><TransHash>F339758901B8452B1C31C168F1361F43</TransHash><TestMode>0</TestMode><UserRef/><AccountNumber/><AccountType/></response>

 

 

 

Have you look at the page source in the web browser when you run your code to see if is get the correct value?

Like I said, I need you to view source on the page in your browser and copy and paste what's actually displaying, so we can make sure nothing's missing. I assume your doCrypto function has scope to all the variables it's referencing? In PHP, for instance, a similar piece of code might require specifying $this->timestamp instead of just $timestamp, and so on.

I'm sorry, when you said page source, I thought you meant source code. The page source does not actually show any of the completed variables, but as you can see... I have the inputs for x_fp_timestamp and x_fp_hash as text so they show up on the page. The fingerprint is being generated and populated into the x_fp_hash, and I have confirmed in the Error 99 Tool that the hash I am generating is the same as the hash a.net would generate if they received the same information.

 

Here is the page source of the form page being sent to a.net. I've editted out some default code generated by SFDC, indicated by ****this****

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>

****Very Top Section**** <meta HTTP-EQUIV="Expires" content="Mon, 01 Jan 1990 12:00:00 GMT" /> <title>Page Editor - CreditCardSend</title>
****Top Section****

 <script> var tabId = getCookie('dmTab'); var closeButtonId = 'thePage:theForm:closeButton'; if (tabId && getBottomPanelHeight() > 28) { showCloseButton(closeButtonId, true); } else { showCloseButton(closeButtonId, false); } function showHideControllerExtensionTabs() { var controllerTab = document.getElementById('thePage:theForm:controllerTab'); if (typeof(controllerTab) != 'undefined' && controllerTab !== null) { controllerTab.style.display = (true) ? 'inline' : 'none'; } document.getElementById('thePage:theForm:extensionTabGroup').style.display = (false) ? 'inline' : 'none'; setTab(); } </script></div><span id="thePage:theForm:source"><textarea id="thePage:theForm:thePageCode" name="thePage:theForm:thePageCode" style="display:none">&lt;apex:page controller="CreditCardController"&gt; &lt;FORM NAME="secure_redirect_form" ID="secure_redirect_form_id" ACTION="https://test.authorize.net/gateway/transact.dll" METHOD="GET"&gt; &lt;label&gt;CreditCardNumber&lt;/label&gt;&lt;input value='370000000000002' type='text' class='text' name='x_card_num' size='15'&gt; &lt;/input&gt; &lt;label&gt;Exp.&lt;/label&gt;&lt;input value='12/15' type='text' class='text' name='x_exp_date' size='4'&gt;&lt;/input&gt; &lt;label&gt;Amount&lt;/label&gt;&lt;input type='text' class='text' name='x_amount' size='9' readonly='true' value='{!amount}'&gt;&lt;/input&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_first_name' VALUE='test' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_last_name' VALUE='test2' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_card_type' VALUE='A' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_card_code' VALUE='4221' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_invoice_num' VALUE='67897654' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_relay_url' VALUE='{!relayResponseUrl}' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_login' VALUE='{!apiLoginId}' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_fp_sequence' VALUE='{!sequence}' /&gt; &lt;INPUT TYPE='text' NAME='x_fp_timestamp' VALUE='{!timestamp}' /&gt; &lt;INPUT TYPE='text' NAME='x_fp_hash' VALUE='{!fingerprint})' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_version' VALUE='3.1' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_method' VALUE='CC' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_type' VALUE='AUTH_CAPTURE' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_market_type' VALUE='2' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_test_request' VALUE='FALSE' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='notes' VALUE='extra hot please' /&gt; &lt;INPUT TYPE='SUBMIT' NAME='buy_button' VALUE='BUY' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_cpversion' VALUE='1.0' /&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_device_type' VALUE='5'/&gt; &lt;INPUT TYPE='HIDDEN' NAME='x_tran_key' VALUE='{!transactionKey}' /&gt; &lt;/form&gt; &lt;/apex:page&gt;</textarea><textarea id="thePage:theForm:theControllerCode" name="thePage:theForm:theControllerCode" style="display:none">public with sharing class CreditCardController { public String input { get; set; } public long timestamp = doTime(); public String sequence = '111'; public String apiLoginId = 'EDITTED OUT'; public String transactionKey = 'EDITTED OUT'; public String receiptPageUrl = 'http://MERCHANT_HOST/order_receipt.jsp'; public String MD5HashKey = apiLoginId; public String amount = '10.00'; public String fingerprint = doCrypto(); public String getFingerprint() { return fingerprint; } public String getTransactionKey() { return transactionKey; } public String getInput() { input = 'seven'; return input; } public long getTimestamp() { return timestamp; } public String getSequence() { return sequence; } public String getApiLoginId() { return apiLoginId; } public String getRelayResponseUrl() { return 'https://c.na14.visual.force.com/apex/CreditCardReturn'; } public String getAmount() { return '10.00'; } public long doTime(){ long timestamp = System.currentTimeMillis() / 1000; return 1329503759; //hardcoded timestamp } public String doCrypto(){ String inputStr = apiLoginId + '^' + sequence + '^' + '1329503759' + '^' + amount + '^';
//hardcoded timestamp String algorithmName = 'hmacMD5'; Blob mac = Crypto.generateMac(algorithmName, Blob.valueOf( inputStr ), Blob.valueOf( transactionKey )); //Convert from Blob to hexadecimal format String String fingerprint = EncodingUtil.convertToHex( mac ); return fingerprint; } }</textarea></span> </div><span id="thePage:theForm:editors"> <div id="pageEditor" style="width: 100%"><span id="thePage:theForm:pageCodeEditor"><script id="thePage:theForm:pageCodeEditor:codeeditor:saveActionFx" type="text/javascript">thePage_theForm_pageCodeEditor_codeeditor_save=function(){A4J.AJAX.Submit('thePage:theForm',null,{'status':'thePage:theForm:saveStatus','oncomplete':function(request,event,data){showHideControllerExtensionTabs()},'similarityGroupingId':'thePage:theForm:pageCodeEditor:codeeditor:saveActionFx','parameters':{'thePage:theForm:pageCodeEditor:codeeditor:saveActionFx':'thePage:theForm:pageCodeEditor:codeeditor:saveActionFx'} } )}; </script> <script> if (typeof(window.editorIds) == "undefined") { window.editorIds = []; } window.componentReferenceUrl = "javascript&colon;openPopupFocus('https://na14.salesforce.com/apexpages/apexcomponents.apexp', 'Help', 700, 600, 'width=700,height=600,resizable=yes,toolbar=yes,status=no,scrollbars=yes,menubar=yes,directories=no,location=no,dependant=no', false, false);"; window.whereIsThisUsedUrl = "javascript&colon;openPopupFocus('https://na14.salesforce.com/_ui/core/apexpages/framework/ApexPageImpactAnalysis/d?id=066d0000000n4uH... 'Help', 700, 600, 'width=700,height=600,resizable=yes,toolbar=yes,status=no,scrollbars=yes,menubar=yes,directories=no,location=no,dependant=no', false, false);"; </script> <textarea id="thePage:theForm:pageCodeEditor:codeeditor:buffer" style="width: 100%; height: 0"></textarea><span id="thePage:theForm:pageCodeEditor:codeeditor:j_id37"> <div class="autocomplete" id="tag_list" style="display:none"></div></span> <script language="javascript" type="text/javascript"> var source = document.getElementById('thePage:theForm:thePageCode'); var bufferId = 'thePage:theForm:pageCodeEditor:codeeditor:buffer'; var buffer = document.getElementById(bufferId); buffer.value = source.value; buffer.disabled = true; var codeEditor = buffer.parentNode; codeEditor.iframeId = 'frame_' + bufferId; if (editorIds.indexOf(codeEditor.id) < 0) { editorIds.push(codeEditor.id); } codeEditor.getValue = function() { return editAreaLoader.getValue('thePage:theForm:pageCodeEditor:codeeditor:buffer'); }; codeEditor.setValue = function(value) { editAreaLoader.setValue('thePage:theForm:pageCodeEditor:codeeditor:buffer', value); }; codeEditor.getSourceElement = function() { return document.getElementById('thePage:theForm:thePageCode'); }; codeEditor.syncFromSource = function() { var source = document.getElementById('thePage:theForm:thePageCode'); this.setValue(source.value); }; codeEditor.syncToSource = function() { var source = document.getElementById('thePage:theForm:thePageCode'); source.value = this.getValue(); }; ****Tons of default page code generated by Salesforce.com****

 

Sorry for the double post, but here is a screenshot of my form page with the information about to be sent (displayed with timestamp and x_hash, which I've copy/pasted into the screenshot so that you can see the entire length of it), and the Error99 troubleshooting tool with the same information populated:

 

 

Wait a minute is that a ) at the end of your x_fp_hash value field.

<INPUT TYPE='text' NAME='x_fp_hash' VALUE='{!fingerprint})' />

 

Try this instead of posting to

https://test.authorize.net/gateway/transact.dll

Post to

https://developer.authorize.net/tools/paramdump/index.php

 

http://developer.authorize.net/tools/datavalidation/

So you can see exactly what you are sending to authorize.net. And view the page source on it and see if there is any white-space on any of the hash key value.

Holy crap! Ask me how bad I feel for spending 2 days changing input values and trying everything else when it turns out to be some monday detail.

 

It still didn't work, but I switched GET to POST and we are cooking with gas now!

 

Thanks guys :)

<apex:page controller="cc_arr_ctrl_Payment_AuthorizeHOP" sidebar="false" showHeader="false" standardStylesheets="false">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
test

<form action="{!gatewayUrl}" method="GET" name="AuthForm" id="AuthForm">
<input type="hidden" name="x_login" value="{!csTransaction.LoginID}" />
<input type="hidden" name="x_version" value="{!csTransaction.version}" />

<INPUT TYPE="hidden" NAME="x_method" VALUE="{!csTransaction.method}"/>
<input type="hidden" name="x_show_form" value="{!csTransaction.showform}" />

<INPUT TYPE="hidden" NAME="x_invoice_num" VALUE="ORDER-002450"/>
<INPUT TYPE="hidden" NAME="x_description" VALUE="Product or order description."/>
<INPUT TYPE="hidden" NAME="x_cust_id" VALUE="Doe-John 001"/>
<INPUT TYPE="hidden" NAME="x_type" VALUE="{!csTransaction.type}"/>

<input type="hidden" name="x_amount" value="{!csTransaction.amount}" />
<input type="hidden" name="x_fp_sequence" value="{!csTransaction.sequence}" />
<input type="hidden" name="x_fp_timestamp" value="{!csTransaction.timeStamp}" />
<input type="hidden" name="x_fp_hash" value="{!csTransaction.hash}" />
<INPUT TYPE="SUBMIT" VALUE="Click here for the secure payment form"/>
<INPUT TYPE="HIDDEN" NAME="x_relay_response" VALUE="true" />

</form>
<script>

});

 


</script>
</apex:page>

 

csTransaction.timeStamp = String.valueOf(System.currentTimeMillis()/1000);
System.debug('--------------x_login='+csTransaction.LoginID);
System.debug('-------------x_tran_key='+TXn_Key);
System.debug('--------------x_fp_timestamp='+System.currentTimeMillis()/1000);
System.debug('--------------x_fp_sequence='+csTransaction.sequence);
System.debug('--------------x_amount='+csTransaction.amount);

String inputStr = csTransaction.LoginID +'^'+random+'^'+System.currentTimeMillis()/1000+'^'+ csTransaction.amount +'^';

System.debug('----------------inputStr='+inputStr);
Blob mac = Crypto.generateMac('hmacMD5',Blob.valueOf(inputStr),Blob.valueOf(TXn_Key));
System.debug('----------------mac='+mac);
//String signature =EncodingUtil.urlEncode(EncodingUtil.convertToHex(mac), 'UTF-8');
String signature = EncodingUtil.convertToHex( mac );

 

reponse code not matching I been trying more than a week can some one help me please

https://developer.authorize.net/tools/responsecode99/#bottom