cancel
Showing results forย 
Search instead forย 
Did you mean:ย 

Definitive guide/key to directResponse fields?

I set up a module to handle break up the direct response and name the various fields according to the pdf documentation. I've noticed that on some exchanges, some of the latter fields seem to have shifted as though one field is now gone moving all the values down by one. Is there a definitive guide to what each of the Direct Response delimited fields represent and do the number of fields ever 'change' for different types of authorization requests? (i.e. a new profile creation vs. a create transaction request etc.)

 

SW

treii28
Contributor
7 REPLIES 7

With a little more digging, I was able to isolate where the 'shift' is dropping in. When I split up the direct response string via the delimeter, I am running into an empty field at array index 39 (40th element) and everything after that is shifted over by one. I was also expecting 68 values (67 delimeters)  and am getting 69 (68 delimeters)

 

Was there a change made that is not yet documented in the AIM/CIM guides?

treii28
Contributor

My guess is they updated the code and you ran foul of extra fields. What you should do probably is download the latest PHP API, look at the list of response fields at the bottom of the AIM lib file, and pass the same version number listed near the top of the code. Hopefully, passing the version number will lock in your fields and prevent the response from updating as Authorize.net adds stuff.

I found the problem which also enlightened why it suddenly changed with my test data. It seems that for some reason the default delimeter for new card/profile authorizations was defaulting to a pipe '|' while for create transaction requests it was defaulting to a comma ','

the problem is that the test data that I'm using included a comma in one of the address fields. I was able to fix the problem yesterday by passing a x_delim_char in the extra options which I was working on at the time anyway. Now I need to look to see if there's a way from the soap side to also guarantee a pipe in the card authorizations. (I'd prefer not to have to rely on a proper administrative tool setting from the aspect of my code - it was working partially because I had an auto-detect in place which would try a couple of common delimeter characters until the number of array elements was over 64 which was the bare minimum I could find in any versions of the service)

 

 

Oh mah gawd! Revisiting this in hopes the implementation was more thorough and the documentation better - I still see the same nightmare of a direct response comma-delimited ambiguity coming back but now it's 64 elements! Yay, I get to try to translate without a guide again!!!

Why in the @#$(( can't you guys come up with some kind of object model for this damn thing? It's soap/xml for goodness sakes! There is no reason that there should be a comma delimited mess coming back! Come into the 21st century and assign key/value pairs or AT LEAST document it!!!

Thanks.

 

After some searching I actually found that link this morning and I also stumbled on a chunk of code that I created last year when I first looked into this and it appears to work with minimal modification to make the string much more usable.

 

<?php
/**
 * Data handler for the Direct Response portion of Authorize.Net payment type validations and authorizations
 * Created by JetBrains PhpStorm.
 * User: scottw
 * Date: 9/29/11
 * Time: 1:59 PM
 * To change this template use File | Settings | File Templates.
 */

namespace ANet\CIM;

class ANet_CIM_Transaction_DirectResponse
{
	/**
	 * key names for portions of the Direct Response
	 *   Note the skips for reserved values - these will be auto-filled with keys
	 *   see http://www.authorize.net/support/AIM_guide.pdf for more information and
	 *   further note that the array keys are offset from the manual by -1
	 *
	 * @var array $keys
	 */
	public static $keys
		= array(
			0  => 'ResponseCode',
			1  => 'ResponseSubCode',
			2  => 'ResponseReasonCode',
			3  => 'ResponseReasonText',
			4  => 'AuthorizationCode',
			5  => 'AVSResponse',
			6  => 'TransactionID',
			7  => 'InvoiceNumber',
			8  => 'Description',
			9  => 'Amount',
			10 => 'Method',
			11 => 'TransactionType',
			12 => 'CustomerID',
			13 => 'FirstName',
			14 => 'LastName',
			15 => 'Company',
			16 => 'Address',
			17 => 'City',
			18 => 'State',
			19 => 'ZIPCode',
			20 => 'Country',
			21 => 'Phone',
			22 => 'Fax',
			23 => 'EmailAddress',
			24 => 'ShipToFirstName',
			25 => 'ShipToLastName',
			26 => 'ShipToCompany',
			27 => 'ShipToAddress',
			28 => 'ShipToCity',
			29 => 'ShipToState',
			30 => 'ShipToZIPCode',
			31 => 'ShipToCountry',
			32 => 'Tax',
			33 => 'Duty',
			34 => 'Freight',
			35 => 'TaxExempt',
			36 => 'PurchaseOrderNumber',
			37 => 'MD5Hash',
			38 => 'CardResponseCode',
			39 => 'CardholderAuthenticationVerificationResponse',

			50 => 'AccountNumber',
			51 => 'CardType',
			52 => 'SplitTenderID',
			53 => 'RequestedAmount',
			54 => 'BalanceOnCard'
		);

	/**
	 * ordered values of direct response stored in array form
	 *
	 * @var array $_dResArr
	 */
	public $_dResArr;
	/**
	 * delimited string version of direct response
	 *
	 * @var string $_dResStr
	 */
	public $_dResStr;
	/**
	 * populated associative array using key names from self::$keys
	 *
	 * @var array $directResponse
	 */
	public $directResponse;

	/**
	 * Constructor to create a new instance of a direct response object
	 *   $dRes can include a delimited string or the exploded array of values in order
	 *
	 * @param null|string|array $dRes
	 * @param string            $delim
	 */
	public function __construct($dRes = null, $delim = 'auto')
	{
		if (!is_null($dRes)) {
			$this->__init($dRes, $delim);
		}
	}

	/**
	 * init method to populate the properties
	 *
	 * @throws Zend_Exception for invalid data
	 *
	 * @param string|array $dRes
	 * @param string       $delim
	 *
	 * @return void
	 */
	public function __init($dRes, $delim = 'auto')
	{
		if (is_string($dRes)) {
			$this->__initFromString($dRes, $delim);
		} elseif (is_array($dRes)) {
			$this->__initFromArray($dRes);
		} else {
			throw new Zend_Exception(__METHOD__ . " input values need to be a delimited string or array of values");
		}
	}

	/**
	 * populate the properties from a delimited string
	 *   explodes the string and uses __initFromArray to do the actual work
	 *
	 * @param string $dResString
	 * @param string $delim  defaults to '|'
	 *
	 * @return void
	 */
	public function __initFromString($dResString, $delim = 'auto')
	{
		//O:37:"Application_Model_ANet_DirectResponse":3:{s:8:"_dResArr";N;s:8:"_dResStr";N;s:14:"directResponse";N;}
		if ($delim === 'auto') {
			foreach (array(',', '|', ':', '\t') as $d) {
				if (substr_count($dResString, $d) > 64) {
					$delim = $d;
				}
			}
		}
		$this->_dResStr = $dResString;
		$this->_dResArr = explode($delim, $dResString);
		$this->__initFromArray($this->_dResArr);
	}

	/**
	 * initialize the properties from an ordered array of values from the direct response
	 *
	 * @param array $dResArr
	 *
	 * @return void
	 */
	public function __initFromArray(array $dResArr)
	{
		$this->_dResArr = $dResArr;
		$this->_dResStr = implode('|', $dResArr);
		foreach ($dResArr as $k=> $v) {
			if (isset(self::$keys[$k])) {
				$prop = self::$keys[$k];
			} else {
				$prop = sprintf("unused%02d", (int)$k+1);
			}
			$this->directResponse[$prop] = $v;
		}
	}

    public function getField($field) {
        if(is_numeric($field) && ((int)$field > 0)) {
            if((int)$field <= count($this->_dResArr)) {
                return $this->_dResArr[$field+1];
            } else {
                throw new \Exception(__METHOD__ . " index does not exist in DirectResponse");
            }
        } elseif((string) $field != '') {
            if(array_key_exists($field, $this->directResponse)) {
                return $this->directResponse[$field];
            } else {
                throw new \Exception(__METHOD__ . " field does not exist in DirectResponse");
            }
        } else {
            throw new \Exception(__METHOD_ . " field name or index required");
        }
    }
}

 

It creates an object from the direct response string when initialized with said string and an optional delimiter string. The separate values can be retrieved with getField() using either the key name or the index (array index + 1 for the php heads). The associative array version is stored in the $directResponse property if sucessfully parsed.  Properties without a designated key are named 'unused{array_index+1}' (using sprintf to force two digits)

 

The original string is stored in _dResStr and the raw array in _dResArr.

Sample object generated by that class:

 

ANet\CIM\ANet_CIM_Transaction_DirectResponse::__set_state(array(
   '_dResArr' => 
  array (
    0 => '1',
    1 => '1',
    2 => '1',
    3 => 'This transaction has been approved.',
    4 => '0OWH97',
    5 => 'Y',
    6 => '2207168060',
    7 => '',
    8 => '',
    9 => '21.59',
    10 => 'CC',
    11 => 'auth_only',
    12 => '52fc73caeb65e39c0020',
    13 => 'SCOTT',
    14 => 'TESTING',
    15 => 'TEST DEVELOPMENT',
    16 => '1234 Fifth Street',
    17 => 'Sixton',
    18 => 'MI',
    19 => '48111',
    20 => 'USA',
    21 => '734-555-1212',
    22 => '',
    23 => 'treii28@somesite.com',
    24 => 'Test',
    25 => 'Order',
    26 => 'TEST ORDER',
    27 => '141 avenue felix faure',
    28 => 'Lyon',
    29 => '',
    30 => '69003',
    31 => 'FRA',
    32 => '',
    33 => '',
    34 => '',
    35 => 'FALSE',
    36 => '',
    37 => '9317B45022AA3180D18A1C75D8273336',
    38 => 'P',
    39 => '2',
    40 => '',
    41 => '',
    42 => '',
    43 => '',
    44 => '',
    45 => '',
    46 => '',
    47 => '',
    48 => '',
    49 => '',
    50 => 'XXXX1881',
    51 => 'Visa',
    52 => '',
    53 => '',
    54 => '',
    55 => '',
    56 => '',
    57 => '',
    58 => '',
    59 => '',
    60 => '',
    61 => '',
    62 => '',
    63 => '',
    64 => '',
    65 => '',
    66 => '',
    67 => '',
    68 => '21952082',
  ),
   '_dResStr' => '1|1|1|This transaction has been approved.|0OWH97|Y|2207168060|||21.59|CC|auth_only|52fc73caeb65e39c0020|SCOTT|TESTING|TEST DEVELOPMENT|1234 Fifth Street|Sixton|MI|48111|USA|734-555-1212||treii28@somesite.com|Test|Order|TEST ORDER|141 avenue felix faure|Lyon||69003|FRA||||FALSE||9317B45022AA3180D18A1C75D8273336|P|2|||||||||||XXXX1881|Visa|||||||||||||||||21952082',
   'directResponse' => 
  array (
    'ResponseCode' => '1',
    'ResponseSubCode' => '1',
    'ResponseReasonCode' => '1',
    'ResponseReasonText' => 'This transaction has been approved.',
    'AuthorizationCode' => '0OWH97',
    'AVSResponse' => 'Y',
    'TransactionID' => '2207168060',
    'InvoiceNumber' => '',
    'Description' => '',
    'Amount' => '21.59',
    'Method' => 'CC',
    'TransactionType' => 'auth_only',
    'CustomerID' => '52fc73caeb65e39c0020',
    'FirstName' => 'SCOTT',
    'LastName' => 'TESTING',
    'Company' => 'TEST DEVELOPMENT',
    'Address' => '1234 Fifth Street',
    'City' => 'Sixton',
    'State' => 'MI',
    'ZIPCode' => '48111',
    'Country' => 'USA',
    'Phone' => '734-555-1212',
    'Fax' => '',
    'EmailAddress' => 'treii28@somesite.com',
    'ShipToFirstName' => 'Test',
    'ShipToLastName' => 'Order',
    'ShipToCompany' => 'TEST ORDER',
    'ShipToAddress' => '141 avenue felix faure',
    'ShipToCity' => 'Lyon',
    'ShipToState' => '',
    'ShipToZIPCode' => '69003',
    'ShipToCountry' => 'FRA',
    'Tax' => '',
    'Duty' => '',
    'Freight' => '',
    'TaxExempt' => 'FALSE',
    'PurchaseOrderNumber' => '',
    'MD5Hash' => '9317B45022AA3180D18A1C75D8273336',
    'CardResponseCode' => 'P',
    'CardholderAuthenticationVerificationResponse' => '2',
    'unused41' => '',
    'unused42' => '',
    'unused43' => '',
    'unused44' => '',
    'unused45' => '',
    'unused46' => '',
    'unused47' => '',
    'unused48' => '',
    'unused49' => '',
    'unused50' => '',
    'AccountNumber' => 'XXXX1881',
    'CardType' => 'Visa',
    'SplitTenderID' => '',
    'RequestedAmount' => '',
    'BalanceOnCard' => '',
    'unused56' => '',
    'unused57' => '',
    'unused58' => '',
    'unused59' => '',
    'unused60' => '',
    'unused61' => '',
    'unused62' => '',
    'unused63' => '',
    'unused64' => '',
    'unused65' => '',
    'unused66' => '',
    'unused67' => '',
    'unused68' => '',
    'unused69' => '21952082',
  ),
))