Integration and Testing

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

Reply
Contributor
Posts: 18
Registered: ‎09-26-2011

AIM API method returning errors with no codes

I'm working on the AIM API method.  It makes it to the process_sale page, but returns errors with no codes.  Any idea where I went wrong?

 

www.mathcelebrity.com/checkout_form.php

 

response code 
response reason code 
response reason text

Expert
Posts: 4,525
Registered: ‎03-08-2010

Re: AIM API method returning errors with no codes

Without showing us process_sale.php code, your guess is as good as our.

 

Contributor
Posts: 18
Registered: ‎09-26-2011

Re: AIM API method returning errors with no codes

<?php

require_once 'coffee_store_settings.php';
require_once 'AuthorizeNetAIM.php';
$METHOD_TO_USE = "AIM";
if ($METHOD_TO_USE == "AIM") {
    $transaction = new AuthorizeNetAIM;
    $transaction->setSandbox(AUTHORIZENET_SANDBOX);
    $transaction->setFields(
        array(
        'amount' => $amount,
        'card_num' => $_POST['x_card_num'],
        'exp_date' => $_POST['exp_month'].$_POST['exp_year'],
        'first_name' => $_POST['x_first_name'],
        'last_name' => $_POST['x_last_name'],
        'address' => $_POST['x_address'],
        'city' => $_POST['x_city'],
        'state' => $_POST['x_state'],
        'country' => $_POST['x_country'],
        'zip' => $_POST['x_zip'],
        'email' => $_POST['x_email'],
        'card_code' => $_POST['x_card_code'],
        )
    );
    $response = $transaction->authorizeAndCapture();
    if ($response->approved) {
        // Transaction approved! Do your logic here.
        // generate passcode
        //$passcode=generate_passcode(9,9); 
        header('Location: thank_you_page.php?transaction_id=' . $response->transaction_id);
    } else {
        header('Location: error_page.php?response_reason_code='.$response->response_reason_code.'&response_code='.$response->response_code.'&response_reason_text=' .$response->response_reason_text);
    }
} elseif (count($_POST)) {
    $response = new AuthorizeNetSIM;
    if ($response->isAuthorizeNet()) {
        if ($response->approved) {
            // Transaction approved! Do your logic here.
            // Redirect the user back to your site.
            $return_url = $site_root . 'thank_you_page.php?transaction_id=' .$response->transaction_id;
        } else {
            // There was a problem. Do your logic here.
            // Redirect the user back to your site.
            $return_url = $site_root . 'error_page.php?response_reason_code='.$response->response_reason_code.'&response_code='.$response->response_code.'&response_reason_text=' .$response->response_reason_text;
        }
        echo AuthorizeNetDPM::getRelayResponseSnippet($return_url);
    } else {
        echo "MD5 Hash failed. Check to make sure your MD5 Setting matches the one in config.php";
    }
}

Posts: 1,609
Topics: 15
Kudos: 209
Solutions: 121
Registered: ‎06-23-2011

Re: AIM API method returning errors with no codes

[ Edited ]

Make a modified version of the page that on error does print_r($response); exit; Then paste us that response. Should tell us what's going on.

 

EDIT: Also put any code or output in a code box - see the fifth icon from the left in Rich Text mode.

Contributor
Posts: 18
Registered: ‎09-26-2011

Re: AIM API method returning errors with no codes

[ Edited ]
AuthorizeNetAIM_Response Object ( [_response_array:private] => Array ( ) [approved] => [declined] => [error] => 1 [held] => [response_code] => [response_subcode] => [response_reason_code] => [response_reason_text] => [authorization_code] => [avs_response] => [transaction_id] => [invoice_number] => [description] => [amount] => [method] => [transaction_type] => [customer_id] => [first_name] => [last_name] => [company] => [address] => [city] => [state] => [zip_code] => [country] => [phone] => [fax] => [email_address] => [ship_to_first_name] => [ship_to_last_name] => [ship_to_company] => [ship_to_address] => [ship_to_city] => [ship_to_state] => [ship_to_zip_code] => [ship_to_country] => [tax] => [duty] => [freight] => [tax_exempt] => [purchase_order_number] => [md5_hash] => [card_code_response] => [cavv_response] => [account_number] => [card_type] => [split_tender_id] => [requested_amount] => [balance_on_card] => [response] => [error_message] => Error connecting to AuthorizeNet ) 

 

I need to include AuthorizeNet.php as well as other files.  Let me add this and repost after re-running this fix.

Posts: 1,609
Topics: 15
Kudos: 209
Solutions: 121
Registered: ‎06-23-2011

Re: AIM API method returning errors with no codes

Aha! Error connecting to Authorize.net. So yes, it's not the code - either the test server is down at the moment (this occasionally happens), or you're not including the correct file.

Contributor
Posts: 18
Registered: ‎09-26-2011

Re: AIM API method returning errors with no codes

AuthorizeNetAIM_Response Object ( [_response_array:private] => Array ( ) [approved] => [declined] => [error] => 1 [held] => [response_code] => [response_subcode] => [response_reason_code] => [response_reason_text] => [authorization_code] => [avs_response] => [transaction_id] => [invoice_number] => [description] => [amount] => [method] => [transaction_type] => [customer_id] => [first_name] => [last_name] => [company] => [address] => [city] => [state] => [zip_code] => [country] => [phone] => [fax] => [email_address] => [ship_to_first_name] => [ship_to_last_name] => [ship_to_company] => [ship_to_address] => [ship_to_city] => [ship_to_state] => [ship_to_zip_code] => [ship_to_country] => [tax] => [duty] => [freight] => [tax_exempt] => [purchase_order_number] => [md5_hash] => [card_code_response] => [cavv_response] => [account_number] => [card_type] => [split_tender_id] => [requested_amount] => [balance_on_card] => [response] => [error_message] => Error connecting to AuthorizeNet ) 

 

My latest response is posted above.  I'm not getting any include errors anymore.  I see that the variables are coming down from the POST, but I think it may be going wrong on authorizeandCapture().  Any thoughts you could provide would be helpful.  Below is my code for AuthorizeNetAIM.php

 

<?php

/**
 * Easily interact with the Authorize.Net AIM API.
 *
 * Example Authorize and Capture Transaction against the Sandbox:
 * <code>
 * <?php require_once 'AuthorizeNet.php'
 * $sale = new AuthorizeNetAIM;
 * $sale->setFields(
 *     array(
 *    'amount' => '4.99',
 *    'card_num' => '411111111111111',
 *    'exp_date' => '0515'
 *    )
 * );
 * $response = $sale->authorizeAndCapture();
 * if ($response->approved) {
 *     echo "Sale successful!"; } else {
 *     echo $response->error_message;
 * }
 * ?>
 * </code>
 *
 * Note: To send requests to the live gateway, either define this:
 * define("AUTHORIZENET_SANDBOX", false);
 *   -- OR -- 
 * $sale = new AuthorizeNetAIM;
 * $sale->setSandbox(false);
 *
 * @package    AuthorizeNet
 * @subpackage AuthorizeNetAIM
 * @link       http://www.authorize.net/support/AIM_guide.pdf AIM Guide
 */

 
/**
 * Builds and sends an AuthorizeNet AIM Request.
 *
 * @package    AuthorizeNet
 * @subpackage AuthorizeNetAIM
 */
class AuthorizeNetAIM extends AuthorizeNetRequest
{

    const LIVE_URL = 'https://secure.authorize.net/gateway/transact.dll';
    const SANDBOX_URL = 'https://test.authorize.net/gateway/transact.dll';
    
    /**
     * Holds all the x_* name/values that will be posted in the request. 
     * Default values are provided for best practice fields.
     */
    protected $_x_post_fields = array(
        "version" => "3.1", 
        "delim_char" => ",",
        "delim_data" => "TRUE",
        "relay_response" => "FALSE",
        "encap_char" => "|",
        );
        
    /**
     * Only used if merchant wants to send multiple line items about the charge.
     */
    private $_additional_line_items = array();
    
    /**
     * Only used if merchant wants to send custom fields.
     */
    private $_custom_fields = array();
    
    /**
     * Checks to make sure a field is actually in the API before setting.
     * Set to false to skip this check.
     */
    public $verify_x_fields = true;
    
    /**
     * A list of all fields in the AIM API.
     * Used to warn user if they try to set a field not offered in the API.
     */
    private $_all_aim_fields = array("address","allow_partial_auth","amount",
        "auth_code","authentication_indicator", "bank_aba_code","bank_acct_name",
        "bank_acct_num","bank_acct_type","bank_check_number","bank_name",
        "card_code","card_num","cardholder_authentication_value","city","company",
        "country","cust_id","customer_ip","delim_char","delim_data","description",
        "duplicate_window","duty","echeck_type","email","email_customer",
        "encap_char","exp_date","fax","first_name","footer_email_receipt",
        "freight","header_email_receipt","invoice_num","last_name","line_item",
        "login","method","phone","po_num","recurring_billing","relay_response",
        "ship_to_address","ship_to_city","ship_to_company","ship_to_country",
        "ship_to_first_name","ship_to_last_name","ship_to_state","ship_to_zip",
        "split_tender_id","state","tax","tax_exempt","test_request","tran_key",
        "trans_id","type","version","zip"
        );
    
    /**
     * Do an AUTH_CAPTURE transaction. 
     * 
     * Required "x_" fields: card_num, exp_date, amount
     *
     * @param string $amount   The dollar amount to charge
     * @param string $card_num The credit card number
     * @param string $exp_date CC expiration date
     *
     * @return AuthorizeNetAIM_Response
     */
    public function authorizeAndCapture($amount = false, $card_num = false, $exp_date = false)
    {
//        ($amount ? $this->amount = $amount : null);
        ($card_num ? $this->card_num = $card_num : null);
        ($exp_date ? $this->exp_date = $exp_date : null);
//$this->amount = $amount;
//$this->exp_date = $exp_date;
//$this->card_num = $card_num;
echo "AIM amount = " .$this->x_amount."<br />";
        $this->type = "AUTH_CAPTURE";
        return $this->_sendRequest();
    }
    
    /**
     * Do a PRIOR_AUTH_CAPTURE transaction.
     *
     * Required "x_" field: trans_id(The transaction id of the prior auth, unless split
     * tender, then set x_split_tender_id manually.)
     * amount (only if lesser than original auth)
     *
     * @param string $trans_id Transaction id to charge
     * @param string $amount   Dollar amount to charge if lesser than auth
     *
     * @return AuthorizeNetAIM_Response
     */
    public function priorAuthCapture($trans_id = false, $amount = false)
    {
        ($trans_id ? $this->trans_id = $trans_id : null);
        ($amount ? $this->amount = $amount : null);
        $this->type = "PRIOR_AUTH_CAPTURE";
        return $this->_sendRequest();
    }

    /**
     * Do an AUTH_ONLY transaction.
     *
     * Required "x_" fields: card_num, exp_date, amount
     *
     * @param string $amount   The dollar amount to charge
     * @param string $card_num The credit card number
     * @param string $exp_date CC expiration date
     *
     * @return AuthorizeNetAIM_Response
     */
    public function authorizeOnly($amount = false, $card_num = false, $exp_date = false)
    {
        ($amount ? $this->amount = $amount : null);
        ($card_num ? $this->card_num = $card_num : null);
        ($exp_date ? $this->exp_date = $exp_date : null);
        $this->type = "AUTH_ONLY";
        return $this->_sendRequest();
    }

    /**
     * Do a VOID transaction.
     *
     * Required "x_" field: trans_id(The transaction id of the prior auth, unless split
     * tender, then set x_split_tender_id manually.)
     *
     * @param string $trans_id Transaction id to void
     *
     * @return AuthorizeNetAIM_Response
     */
    public function void($trans_id = false)
    {
        ($trans_id ? $this->trans_id = $trans_id : null);
        $this->type = "VOID";
        return $this->_sendRequest();
    }
    
    /**
     * Do a CAPTURE_ONLY transaction.
     *
     * Required "x_" fields: auth_code, amount, card_num , exp_date
     *
     * @param string $auth_code The auth code
     * @param string $amount    The dollar amount to charge
     * @param string $card_num  The last 4 of credit card number
     * @param string $exp_date  CC expiration date
     *
     * @return AuthorizeNetAIM_Response
     */
    public function captureOnly($auth_code = false, $amount = false, $card_num = false, $exp_date = false)
    {
        ($auth_code ? $this->auth_code = $auth_code : null);
        ($amount ? $this->amount = $amount : null);
        ($card_num ? $this->card_num = $card_num : null);
        ($exp_date ? $this->exp_date = $exp_date : null);
        $this->type = "CAPTURE_ONLY";
        return $this->_sendRequest();
    }
    
    /**
     * Do a CREDIT transaction.
     *
     * Required "x_" fields: trans_id, amount, card_num (just the last 4)
     *
     * @param string $trans_id Transaction id to credit
     * @param string $amount   The dollar amount to credit
     * @param string $card_num The last 4 of credit card number
     *
     * @return AuthorizeNetAIM_Response
     */
    public function credit($trans_id = false, $amount = false, $card_num = false)
    {
        ($trans_id ? $this->trans_id = $trans_id : null);
        ($amount ? $this->amount = $amount : null);
        ($card_num ? $this->card_num = $card_num : null);
        $this->type = "CREDIT";
        return $this->_sendRequest();
    }
    
    /**
     * Alternative syntax for setting x_ fields.
     *
     * Usage: $sale->method = "echeck";
     *
     * @param string $name
     * @param string $value
     */
    public function __set($name, $value) 
    {
        $this->setField($name, $value);
    }
    
    /**
     * Quickly set multiple fields.
     *
     * Note: The prefix x_ will be added to all fields. If you want to set a
     * custom field without the x_ prefix, use setCustomField or setCustomFields.
     *
     * @param array $fields Takes an array or object.
     */
    public function setFields($fields)
    {
        $array = (array)$fields;
        foreach ($array as $key => $value) {
echo "key = " . $key . " and value = ".$value . "<br />";
            $this->setField($key, $value);
        }
    }
    
    /**
     * Quickly set multiple custom fields.
     *
     * @param array $fields
     */
    public function setCustomFields($fields)
    {
        $array = (array)$fields;
        foreach ($array as $key => $value) {
            $this->setCustomField($key, $value);
        }
    }
    
    /**
     * Add a line item.
     * 
     * @param string $item_id
     * @param string $item_name
     * @param string $item_description
     * @param string $item_quantity
     * @param string $item_unit_price
     * @param string $item_taxable
     */
    public function addLineItem($item_id, $item_name, $item_description, $item_quantity, $item_unit_price, $item_taxable)
    {
        $line_item = "";
        $delimiter = "";
        foreach (func_get_args() as $key => $value) {
            $line_item .= $delimiter . $value;
            $delimiter = "<|>";
        }
        $this->_additional_line_items[] = $line_item;
    }
    
    /**
     * Use ECHECK as payment type.
     */
    public function setECheck($bank_aba_code, $bank_acct_num, $bank_acct_type, $bank_name, $bank_acct_name, $echeck_type = 'WEB')
    {
        $this->setFields(
            array(
            'method' => 'echeck',
            'bank_aba_code' => $bank_aba_code,
            'bank_acct_num' => $bank_acct_num,
            'bank_acct_type' => $bank_acct_type,
            'bank_name' => $bank_name,
            'bank_acct_name' => $bank_acct_type,
            'echeck_type' => $echeck_type,
            )
        );
    }
    
    /**
     * Set an individual name/value pair. This will append x_ to the name
     * before posting.
     *
     * @param string $name
     * @param string $value
     */
    public function setField($name, $value)
    {
        if ($this->verify_x_fields) {
            if (in_array($name, $this->_all_aim_fields)) {
                $this->_x_post_fields[$name] = $value;
            } else {
                throw new AuthorizeNetException("Error: no field $name exists in the AIM API.
                To set a custom field use setCustomField('field','value') instead.");
            }
        } else {
            $this->_x_post_fields[$name] = $value;
        }
    }
    
    /**
     * Set a custom field. Note: the x_ prefix will not be added to
     * your custom field if you use this method.
     *
     * @param string $name
     * @param string $value
     */
    public function setCustomField($name, $value)
    {
        $this->_custom_fields[$name] = $value;
    }
    
    /**
     * Unset an x_ field.
     *
     * @param string $name Field to unset.
     */
    public function unsetField($name)
    {
        unset($this->_x_post_fields[$name]);
    }
    
    /**
     *
     *
     * @param string $response
     * 
     * @return AuthorizeNetAIM_Response
     */
    protected function _handleResponse($response)
    {
        return new AuthorizeNetAIM_Response($response, $this->_x_post_fields['delim_char'], $this->_x_post_fields['encap_char'], $this->_custom_fields);
    }
    
    /**
     * @return string
     */
    protected function _getPostUrl()
    {
        return ($this->_sandbox ? self::SANDBOX_URL : self::LIVE_URL);
    }
    
    /**
     * Converts the x_post_fields array into a string suitable for posting.
     */
    protected function _setPostString()
    {
        $this->_x_post_fields['login'] = $this->_api_login;
        $this->_x_post_fields['tran_key'] = $this->_transaction_key;
        $this->_post_string = "";
        foreach ($this->_x_post_fields as $key => $value) {
            $this->_post_string .= "x_$key=" . urlencode($value) . "&";
        }
        // Add line items
        foreach ($this->_additional_line_items as $key => $value) {
            $this->_post_string .= "x_line_item=" . urlencode($value) . "&";
        }
        // Add custom fields
        foreach ($this->_custom_fields as $key => $value) {
            $this->_post_string .= "$key=" . urlencode($value) . "&";
        }
        $this->_post_string = rtrim($this->_post_string, "& ");
    }
}

/**
 * Parses an AuthorizeNet AIM Response.
 *
 * @package    AuthorizeNet
 * @subpackage AuthorizeNetAIM
 */
class AuthorizeNetAIM_Response extends AuthorizeNetResponse
{
    private $_response_array = array(); // An array with the split response.

    /**
     * Constructor. Parses the AuthorizeNet response string.
     *
     * @param string $response      The response from the AuthNet server.
     * @param string $delimiter     The delimiter used (default is ",")
     * @param string $encap_char    The encap_char used (default is "|")
     * @param array  $custom_fields Any custom fields set in the request.
     */
    public function __construct($response, $delimiter, $encap_char, $custom_fields)
    {
        if ($response) {
            
            // Split Array
            $this->response = $response;
            if ($encap_char) {
                $this->_response_array = explode($encap_char.$delimiter.$encap_char, substr($response, 1, -1));
            } else {
                $this->_response_array = explode($delimiter, $response);
            }
            
            /**
             * If AuthorizeNet doesn't return a delimited response.
             */
            if (count($this->_response_array) < 10) {
                $this->approved = false;
                $this->error = true;
                $this->error_message = "Unrecognized response from AuthorizeNet: $response";
                return;
            }
            
            
            
            // Set all fields
            $this->response_code        = $this->_response_array[0];
            $this->response_subcode     = $this->_response_array[1];
            $this->response_reason_code = $this->_response_array[2];
            $this->response_reason_text = $this->_response_array[3];
            $this->authorization_code   = $this->_response_array[4];
            $this->avs_response         = $this->_response_array[5];
            $this->transaction_id       = $this->_response_array[6];
            $this->invoice_number       = $this->_response_array[7];
            $this->description          = $this->_response_array[8];
            $this->amount               = $this->_response_array[9];
            $this->method               = $this->_response_array[10];
            $this->transaction_type     = $this->_response_array[11];
            $this->customer_id          = $this->_response_array[12];
            $this->first_name           = $this->_response_array[13];
            $this->last_name            = $this->_response_array[14];
            $this->company              = $this->_response_array[15];
            $this->address              = $this->_response_array[16];
            $this->city                 = $this->_response_array[17];
            $this->state                = $this->_response_array[18];
            $this->zip_code             = $this->_response_array[19];
            $this->country              = $this->_response_array[20];
            $this->phone                = $this->_response_array[21];
            $this->fax                  = $this->_response_array[22];
            $this->email_address        = $this->_response_array[23];
            $this->ship_to_first_name   = $this->_response_array[24];
            $this->ship_to_last_name    = $this->_response_array[25];
            $this->ship_to_company      = $this->_response_array[26];
            $this->ship_to_address      = $this->_response_array[27];
            $this->ship_to_city         = $this->_response_array[28];
            $this->ship_to_state        = $this->_response_array[29];
            $this->ship_to_zip_code     = $this->_response_array[30];
            $this->ship_to_country      = $this->_response_array[31];
            $this->tax                  = $this->_response_array[32];
            $this->duty                 = $this->_response_array[33];
            $this->freight              = $this->_response_array[34];
            $this->tax_exempt           = $this->_response_array[35];
            $this->purchase_order_number= $this->_response_array[36];
            $this->md5_hash             = $this->_response_array[37];
            $this->card_code_response   = $this->_response_array[38];
            $this->cavv_response        = $this->_response_array[39];
            $this->account_number       = $this->_response_array[50];
            $this->card_type            = $this->_response_array[51];
            $this->split_tender_id      = $this->_response_array[52];
            $this->requested_amount     = $this->_response_array[53];
            $this->balance_on_card      = $this->_response_array[54];
            
            $this->approved = ($this->response_code == self::APPROVED);
            $this->declined = ($this->response_code == self::DECLINED);
            $this->error    = ($this->response_code == self::ERROR);
            $this->held     = ($this->response_code == self::HELD);
            
            // Set custom fields
            if ($count = count($custom_fields)) {
                $custom_fields_response = array_slice($this->_response_array, -$count, $count);
                $i = 0;
                foreach ($custom_fields as $key => $value) {
                    $this->$key = $custom_fields_response[$i];
                    $i++;
                }
            }
            
            if ($this->error) {
                $this->error_message = "AuthorizeNet Error:
                Response Code: ".$this->response_code."
                Response Subcode: ".$this->response_subcode."
                Response Reason Code: ".$this->response_reason_code."
                Response Reason Text: ".$this->response_reason_text."
                ";
            }
        } else {
            $this->approved = false;
            $this->error = true;
            $this->error_message = "Error connecting to AuthorizeNet";
        }
    }

}

 

Posts: 1,609
Topics: 15
Kudos: 209
Solutions: 121
Registered: ‎06-23-2011

Re: AIM API method returning errors with no codes

[ Edited ]

Not going to read the huge wall of code. Here's my implementation for AIM, should work with the SDK right out of the box unless they made some major changes in the last few months.

 

NOTE: This is for the production server. If using with sandbox, set sandbox to true and use a CCV of 900.

 

require_once($_SERVER['DOCUMENT_ROOT'] . '/library/globals.php');
// Includes my Authorize.net ID and key

require_once($_SERVER['DOCUMENT_ROOT'] . '/library/anet_php_sdk/AuthorizeNet.php');
// Path to main file of Authorize.net PHP SDK

$authorize = new AuthorizeNetAIM( $GLOBALS['_authorize_id'], $GLOBALS['_authorize_key']); $authorize->setSandbox(false); $fields = array( 'first_name' => $_POST['first'], 'last_name' => $_POST['last'], 'company' => $_POST['company'], 'address' => $_POST['address'], 'city' => $_POST['city'], 'state' => $_POST['state'], 'zip' => $_POST['zip'], 'country' => 'US', 'phone' => $_POST['phone'], 'email' => $_POST['email'], 'customer_ip' => $_SERVER['REMOTE_ADDR'], 'description' => "{$_POST['type']} initial fee for " . count($_POST['zips']) . " zip codes with {$population} total estimated population", 'amount' => $_POST['initial_payment'], 'card_num' => $_POST['card_number'], 'exp_date' => sprintf('%02d%02d', $_POST['card_exp_month'], ($_POST['card_exp_year'] % 1000)), 'card_code' => $_POST['card_ccv'] ); $authorize->setFields($fields); $result = $authorize->authorizeAndCapture(); if ($result->error || $result->{'response_code'} != 1) $errors[] = "Initial charge declined - {$result->response_reason_text}";

 

Contributor
Posts: 18
Registered: ‎09-26-2011

Re: AIM API method returning errors with no codes

I had to set VERIFY_PEER = false.  Do I need an SSL cert when it's time to go live?

 

Also, I now get this response after doing that:

 

Response Code: 3 Response Subcode: 2 Response Reason Code: 13 Response Reason Text: The merchant login ID or password is invalid or the account is inactive

 

Contributor
Posts: 18
Registered: ‎09-26-2011

Re: AIM API method returning errors with no codes

I found this documentation for reason code 13:

 

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

 

Do I need to point to the live url?  I have sandbox set to true right now.