Tutorial: Integrate All Authorize.Net JSON APIs With One Universal PHP Package (AIM, ARB, CIM, Transaction Details)

GithubIf you find this tutorial and code useful, please take a moment to star it on Github. If you want to help develop it futher, fork it.

Three years ago I published code and an article for integrating the Authorize.Net APIs using PHP. This simplified interacting with Authorize.Net’s APIs by using their common XML interface. But many developers asked for a simpler API, one that used JSON instead of XML. In November of 2014 Authorize.Net delivered by announcing their new JSON format APIs. This blog post announces a new library to work with this new format.

Getting Started With The AuthnetJson Class

Requirements

  • PHP 7.2 or newer (there is a PHP 5.6 compatible release as well)
  • cURL PHP Extension
  • SimpleXML
  • Composer (optional)

If you don’t already have one, sign up for an Authorize.Net Developer Account. This will allow you to test your code without having an actual Authorize.Net account or incurring any processing fees.

Included in the AuthnetJson Package is sample code for every API call supported by the class (AIM, ARB, CIM, and Transaction Detail). They all work in the same manner with the only differences being the information required and response returned for that particular API call. So, to demonstrate how an API call is made using the AuthnetJson package, we will make a call to the CIM API to create a customer profile and handle the response.

Installation Option #1: Using Composer

Simply add a dependency on stymiee/authnetjson to your project’s composer.json file if you use Composer to manage the dependencies of your project. Here is a minimal example of a composer.json file that just defines a dependency on AuthnetJson (make sure to use the most recent version of the package):

{
    "require": {
        "stymiee/authnetjson": "^4"
    }
}

Installation Option #2: Download the package from Github

Download the AuthnetJson Package which includes the AuthnetJson code from Github.

For the sake of this tutorial we will execute a script through the browser and see the results to help conceptualize how this script works.

Getting started with an example included in the repository

To get started you will need to set the credentials for your Authorize.Net developer account in the configuration file included in the AuthnetJson package. This file is not required for using the AuthnetJson package in your application but is provided for convenience when viewing the examples included in this package. Simply fill in the values shown in the lines below.

defined('AUTHNET_LOGIN')    || define('AUTHNET_LOGIN', '');    
defined('AUTHNET_TRANSKEY') || define('AUTHNET_TRANSKEY', '');

Once you have configured your login and transaction key you will be able to run the examples included in the repository.

Some of the examples require the values returned when running other examples to be provided to work correctly. For example, the example demonstrating the deletCustomerProfileRequest API call will not work unless the createCustomerProfile API call is run first and the profile ID obtained in that APi call are provided (i.e. manually editted into) the deletCustomerProfileRequest example.

Viewing an example in the web browser

We will start by viewing a Authorize and Capture (i.e. purchase) API call in our web browser. To view this example we need to open the createTransactionRequest_authCapture API call example which can be found in the examples/aim directory within the repository. You can view it in your browser by visiting http://localhost/examples/aim/createTransactionRequest_authCapture.php in your favorite web browser. (Replace localhost with the URL and path to your AuthnetJson installation).

You should see results similar to this:

Response Ok
Successful? yes
Error? no
Description This transaction has been approved.
authCode EYR4ZI
transId 2232771154

Raw Input/Output

Class Parameters
API Login ID asdfgh1234556
Transaction Key gsdfdgsgbe6nm6ue7mi8
Authnet Server URL https://apitest.authorize.net/xml/v1/request.api
Request JSON
{“createTransactionRequest”:{“merchantAuthentication”:{“name”:”cnpdev1234″,”transactionKey”:”dEn7vFLQSR2P8g4j”},”refId”:97428925,”transactionRequest”:{“transactionType”:”authCaptureTransaction”,”amount”:5,”payment”:{“creditCard”:{“cardNumber”:”4111111111111111″,”expirationDate”:”122016″,”cardCode”:”999″}},”order”:{“invoiceNumber”:”1324567890″,”description”:”this is a test transaction”},”lineItems”:{“lineItem”:[{“itemId”:”1″,”name”:”vase”,”description”:”Cannes logo”,”quantity”:”18″,”unitPrice”:”45.00″},{“itemId”:”2″,”name”:”desk”,”description”:”Big Desk”,”quantity”:”10″,”unitPrice”:”85.00″}]},”tax”:{“amount”:”4.26″,”name”:”level2 tax name”,”description”:”level2 tax”},”duty”:{“amount”:”8.55″,”name”:”duty name”,”description”:”duty description”},”shipping”:{“amount”:”4.26″,”name”:”level2 tax name”,”description”:”level2 tax”},”poNumber”:”456654″,”customer”:{“id”:”18″,”email”:”someone@blackhole.tv”},”billTo”:{“firstName”:”Ellen”,”lastName”:”Johnson”,”company”:”Souveniropolis”,”address”:”14 Main Street”,”city”:”Pecan Springs”,”state”:”TX”,”zip”:”44628″,”country”:”USA”},”shipTo”:{“firstName”:”China”,”lastName”:”Bayles”,”company”:”Thyme for Tea”,”address”:”12 Main Street”,”city”:”Pecan Springs”,”state”:”TX”,”zip”:”44628″,”country”:”USA”},”customerIP”:”192.168.1.1″,”transactionSettings”:{“setting”:[{“settingName”:”allowPartialAuth”,”settingValue”:”false”},{“settingName”:”duplicateWindow”,”settingValue”:”0″},{“settingName”:”emailCustomer”,”settingValue”:”false”},{“settingName”:”recurringBilling”,”settingValue”:”false”},{“settingName”:”testRequest”,”settingValue”:”false”}]},”userFields”:{“userField”:{“name”:”favorite_color”,”value”:”blue”}}}}}
Response JSON
{“transactionResponse”:{“responseCode”:”1″,”authCode”:”EYR4ZI”,”avsResultCode”:”Y”,”cvvResultCode”:”P”,
“cavvResultCode”:”2″,transId”:”2232771154″,”refTransID”:””,”transHash”:
“3C80D1ED00E838B1791EACF403AA7A62″,”testRequest”:”0″,”accountNumber”:”XXXX1111″,”accountType”:
“Visa”,”messages”:[{“code”:”1″,”description”:”This transaction has been
approved.”}],”userFields”:[{“name”:”favorite_color”,”value”:”blue”}]},”refId”:”97428925″,
“messages”:{“resultCode”:”Ok”, “message”:[{“code”:”I00001″,”text”:”Successful.”}]}}

What you are looking at is four key components of our API call:

  • A basic summary of our API call
  • The Authorize.Net user credentials and API endpoint we are hitting
  • The request JSON
  • The response JSON

The basic summary of the API call shows key elements of the API response so we can verify it is what we are expecting. In the case shown above we can see we get an Ok response from Authorize.Net which means our transaction was successful. This is reiterated by the output of our isSuccessful() and isError() method calls. Commonly used information about the transaction is then displayed including the authorization code provided by the bank and the transaction ID provided by Authorize.Net.

The next component displays our user credentials. This allows us to troubleshoot any connectivity or authorization issues that may arise.

The last two sections show our JSON request as sent to Authorize.Net and Authorize.Net’s JSON response.

So how did we get all of this information? Let’s examine the code.

A sample API call

Open the createTransactionRequest_authCapture.php file we used in the example located in the /examples/aim/ directory. After the copyright you will see a comment which contains two pieces of information.

  1. First is the request JSON we want to send to Authorize.Net. In this case it is using their AIM API to process an Authorize and Capture transaction. The format and required fields are dictated in the associated documentation.
  2. Second is the response we expect when we make a valid and successful API. (The response you get will differ slightly from what is shown here as dynamic and unique values like dates and transaction IDs cannot be same same).

It’s these two pieces of JSON that this class creates and parses for us so we don’t have to do it in your payment processing code.

You will then see that the file sets the namespace to JohnConde\Authnet. Since all of the files needed for this example are located in the same namespace we work from there. Your project will probably be working with files from multiple namespaces so you most like would be using the use statement to import/alias the namespace or classes (e.g. use JohnConde\Authnet\AuthnetJson) or just use the fully qualified namespace names containing namespace separator (e.g. $request = JohnConde\Authnet\AuthnetApiFactory::getJsonApiHandler(...);).

This is followed by two require statements:

require('../../config.inc.php');
require('../../src/autoload.php');
  1. The first is a simple configuration file which is only used in the examples to make setup easier for me (and for you). If you place your Authorize.Net API credentials directly inside the code you can omit this statement.
  2. The second is the autoloader which (as the name implies) will autoload all of the AuthnetJson classes dynamically as our code needs them. (If you use composer to install the AuthnetJson Package you only need to include the autoload file in your vendor directory).
$request = AuthnetApiFactory::getJsonApiHandler(
    AUTHNET_LOGIN, 
    AUTHNET_TRANSKEY,
    AuthnetApiFactory::USE_DEVELOPMENT_SERVER
);

The next line creates our request object prepares it to make an API call. This factory class will take up to three parameters which will be used to build an object that we will use to interact with the Authorize.Net APIs. Those three parameters are:

  1. The Authorize.Net API login and transaction key. These are provided in the Authorize.Net control panel. They are not the same as the login and password used to access the control panel. The login and transaction key used in the production environment will be different from the ones used in development.
  2. The third parameter is optional and determines which API endpoint our code will be using. If it is being executed in a development, testing, or staging environment we would want to use the developer endpoint. If your code is in production we would want to use the production endpoint. The default is the to use the production endpoint (either leave this parameter empty, set it to 0, or use the built in AuthnetApiFactory::USE_PRODUCTION_SERVER. To use the developer endpoint you can pass 1 or AuthnetApiFactory::USE_DEVELOPMENT_SERVER).

Once the request object is created we can execute our request. But to do that we need to determine which API call we are going to make and provide the data in the required format as specified in Authorize.Net’s documentation. To do that we take advantage of PHP’s __call() magic method. Using __call() we can make the API call we wish to make the name of the method our $request object calls and pass our data as a parameter to that method call.

$response = $request->createTransactionRequest(array(
    'transactionRequest' => array(
        'transactionType' => 'authCaptureTransaction',
        'amount' => 5,
        'payment' => array(
            'creditCard' => array(
                'cardNumber' => '4111111111111111',
                'expirationDate' => '122019',
                'cardCode' => '999',
            ),
        ),
    ),
));

The example above creates a call to the createTransactionRequest endpoint to make an AUTH_CAPTURE transaction (represented as authCaptureTransaction) for $5.00 using a credit card with the number 4111111111111111 that expires in December 2109 and has a CVV number of 999. (To see a full example of all the parameters createTransactionRequest() is accepting in the example used above, view the source code of /examples/aim/createTransactionRequest_authCapture.php in the AuthnetJson repository).

The structure of the request, which is the array we pass to createTransactionRequest(), is determined by the Authorize.Net API Reference. It does a good job of showing the proper structure of a request and provides both JSON and XML examples for reference. You can find examples of every API call in the /examples directory of the AuthnetJson Package.

Once the transaction is processed we need to check the results. There are three possible outcomes of a transaction:

  1. The transaction was successful and the transaction was approved
  2. The transaction was successful and the transaction was declined or there was an error
  3. The transaction was unsuccessful because there was a fatal error

The transaction was successful and the transaction was approved

When making any API call it will either be successful or not. Checking if an API call was successful, which means the API call worked and returned a “success” message, can be done using $response->isSuccessful(). In the case of making a payment this is not enough to determine if the payment was approved. To do this we would need to use $response->isApproved(). A payment transaction can be successful but not approved so it is important to check both when verifying a transaction is approved.

The transaction was successful but the transaction was declined or there was an error

A transaction that receives a valid response from the Authorize.Net API is considered successful. But this does not mean the results are positive. A successful API call may still result in a transaction being declined (for purchases) or result in an error. An error can be varied in cause but are most commonly due to missing or incorrect values being passed to the API. You should explicitly check for these results in your code (as opposed to only checking for a successful or approved transaction).

You can check to see if a transaction is declined by using $response->isDeclined() after the transaction has been processed. Similarly you can check if there was an error using $response->isError() (which is the equivalent of !$response->isSuccessful()). Although both indicate a failed payment you should explicitly check for each scenario as how you handle them from a business perspective will be different. (i.e. If a transaction is declined you can ask for another form of payment. If there was an error you can log it and have someone from support contact the user to complete the transaction).

The transaction was unsuccessful because there was a fatal error

If there is an error before, and sometimes after, the transaction that cannot be handled an exception will be thrown. This will allow you to automatically clean up if necessary (i.e. void a payment transaction or rollback a database transaction). The following exceptions are included in the AuthnetJson Package:

  • AuthnetCannotSetParamsException – Thrown when when client code attempts to set a parameter directly (i.e. using __set())
  • AuthnetCurlException – Thrown when cURL experiences an unexpected error
  • AuthnetInvalidCredentialsException – Thrown when invalid Authorize.Net API credentials are provided
  • AuthnetInvalidJsonException – Thrown when invalid JSON is returned by the API
  • AuthnetInvalidServerException – Thrown when an invalid value is given for the $server parameter when initiating an instance of the AuthnetJson class
  • AuthnetTransactionResponseCallException – Thrown when transaction response data is requested on an API call that does not return any
  • AuthnetException – Generic Exception that may be thrown whenever an unexpected error occurs using the AuthnetJson package

Once a transaction has successfully been processed you probably will want to access some of the response values returned for auditing purposes. You can access them in the $response object returned from each transaction. Two common examples are the authorization code for an approved authorize and capture ($response->transactionResponse->authCode) and the transaction ID of a transaction ($response->transactionResponse->transId).

The structure of the response follows a similar construct as our request and is also described in the Authorize.Net API Reference. You can see the most common examples in the /examples directory of the AuthnetJson Package.

The unit tests contain even more. If you want a more in depth understanding of how this code works, reading the unit tests can be enlightening.

Support

I want to make sure this code is bug free and easy to use and helping others use it is a great way to ensure that. If you are having difficulty using this code please do not contact me through this website. Since this software is free to the community, the community can assist me in supporting it. I am an active participant at StackOverflow. Others also frequent it who are also capable of assisting you with this code. When posting your question there, or anywhere for that matter, be sure to include the following:

  • A link to either this tutorial and/or the GitHub repository so others can see what software you are using and can download it if necessary so if they attempt to reproduce the problem you are having.
  • Your code as it is implemented in your software. Make sure you format it so it is readable by others.
  • A description of what you are expecting your code to do (but it is not happening).
  • Any error message you are getting.

Leave a Reply

Your email address will not be published. Required fields are marked *