Tutorial: Integrate the Authorize.Net CIM API with PHP

Just like Authorize.Net’s Advanced Integration Method (AIM) API and Automated Recurring Billing (ARB) APIs, working with their Customer Information Manager (CIM) API isn’t difficult if you have suitable code to work with. The sample code offered by Authorize.Net will demonstrate how to work with their API but is not production ready. As with their AIM API and ARB API I have created a class that abstracts their CIM API into something easier to use and maintain.

To follow this tutorial and integrate CIM API into your PHP website follow these steps:

  1. If you don’t already have one sign up for a Authorize.Net Developer Account. This will allow you to test your code without having an actual Authorize.Net account or incurring any processing fees.
  2. Download the CIM Integration Guide (for reference)
  3. Download the PHP code for CIM

To begin you will need to include the class using PHP’s require() function:

1
require('AuthnetCIM.class.php');

As with any class/object the first thing we need to do is instantiate it. Up to three parameters are accepted in the constructor with the first two being required. myapilogin is the API login for the account. mYtRaNsaCTiOnKEy is the transaction key generated in the Authorize.Net control panel (or assigned to you with your test account information). If you have an Authorize.Net developer account you can use it with this script by setting the third parameters to TRUE (you may omit the third parameter if you are using this with the live server):

1
$payment = new AuthnetCIM('myapilogin', 'mYtRaNsaCTiOnKEy', true);

There are quite a few things you can do through the CIM API all of which fall into one of three categories: createXXXXXXX, updateXXXXXX, and deleteXXXXXX where XXXXXXX is the request type (CustomerProfileRequest, CustomerPaymentProfileRequest, CustomerShippingAddressRequest, and CustomerProfileTransactionRequest). Since updating a profile is almost identical to creating a profile (you just call a updateXXXXXX instead of createXXXXXX) and deleting a profile is very straightforward this tutorial will focus solely on the creating of profiles and processing payments.

There can be as many as four API calls to create profiles and process a payment although only three are actually necessary. They are:

  1. createCustomerProfile() – Creates the customer’s payment profile which serves as their master record. There should be only one payment profile per customer.
  2. createCustomerPaymentProfile() – Creates a payment profile for a customer. There should be one of these for every credit card or checking account the customer wishes to use.
  3. createCustomerShippingAddress() – (Optional) Creates a shipping profile for a customer. There should be one of these for every shipping address the customer wishes to use.
  4. createCustomerProfileTransaction() – Processes a transaction for a customer.

Before we can process any payments for a customer we must create their main profile. There are two fields you should provide although I am going to show three since combined they serve a significant purpose. These three fields are important because if all three fields match another profile exactly, meaning all three fields are identical between both profiles in every way, the profile will not be created. If one of the fields is different, it doesn’t matter which one, the profile will be created.

To create customer profile you can use this code (naturally you can change the values passed to each parameter):

1
2
3
4
5
$cim->setParameter('email', 'fakeemail@example.com');
$cim->setParameter('description', 'Profile for Joe Smith'); // Optional
$cim->setParameter('merchantCustomerId', '123456789');
$cim->createCustomerProfile();
$profile_id = $cim->getProfileID();

The first three lines set the necessary parameters for createCustomerProfile() to function properly. email is the customer email address, description is a description of the profile, and merchantCustomerId is your customer ID number (e.g. one generated by your system). The fourth line calls the CIM API to create the customer profile. The fifth line retrieves the customer profile ID created by Authorize.Net. This number is important as it is required to process all CIM requests for this profile. This means you should store it along with any other data you store in your database for this customer.

Now that we have created our customer profile we need to create at least one payment profile to use to process their payments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$cim->setParameter('customerProfileId', $profile_id);
$cim->setParameter('billToFirstName', 'Joe');
$cim->setParameter('billToLastName', 'Smith');
$cim->setParameter('billToAddress', '123 Main Street');
$cim->setParameter('billToCity', 'Townsville');
$cim->setParameter('billToState', 'NJ');
$cim->setParameter('billToZip', '12345');
$cim->setParameter('billToCountry', 'US');
$cim->setParameter('billToPhoneNumber', '800-555-1234');
$cim->setParameter('billToFaxNumber', '800-555-2345');
$cim->setParameter('cardNumber', '4111111111111111');
$cim->setParameter('expirationDate', '2016-12');
$cim->createCustomerPaymentProfile();
$payment_profile_id = $cim->getPaymentProfileId();

The first line refers to the profile we wish to attach this payment profile to. The next nine lines set the billing information for the user’s credit card including their billing address (i.e. the address they have on file with their credit card issuing bank). The next two lines set the credit card information for the payment profile. The last two lines call the CIM API to create the payment profile and retrieve its ID which should be stored in your database.

Now we can create our shipping profile:

1
2
3
4
5
6
7
8
9
10
11
12
$cim->setParameter('customerProfileId', $profile_id);
$cim->setParameter('shipToFirstName', 'Joe');
$cim->setParameter('shipToLastName', 'Smith');
$cim->setParameter('shipToAddress', '123 Main Street');
$cim->setParameter('shipToCity', 'Townsville');
$cim->setParameter('shipToState', 'NJ');
$cim->setParameter('shipToZip', '12345');
$cim->setParameter('shipToCountry', 'US');
$cim->setParameter('shipToPhoneNumber', '800-555-1234');
$cim->setParameter('shipToFaxNumber', '800-555-2345');
$cim->createCustomerShippingAddress();
$shipping_profile_id = $cim->getCustomerAddressId();

Since creating a shipping profile is nearly identical to creating a billing profile I won’t elaborate on it other then to say the names of the parameters are different and no payment information is provided.

The final step is to process a payment:

1
2
3
4
5
6
$cim->setParameter('amount', $purchase_amount);
$cim->setParameter('customerProfileId', $profile_id);
$cim->setParameter('customerPaymentProfileId', $payment_profile_id);
$cim->setParameter('customerShippingAddressId', $shipping_profile_id);
$cim->createCustomerProfileTransaction();
$approval_code = $cim->getAuthCode();

This is pretty straight forward. We start by setting the amount we wish to charge. Then we tell the CIM API which customer profile, payment profile, and shipping profile to use. Finally we use the CIM API to process the transaction and we retrieve the approval code.

The AuthnetCIM class takes advantage of exceptions which are new in PHP5. These are only generated when an “exceptional” event occurs. The only exceptional event that might occur when using this class is cURL may fail. This may be due to server, network, or user errors. To catch these exceptions and handle them use code similar to this:

1
2
3
4
5
6
7
8
9
10
try
{
    $cim = new AuthnetCIM('myapilogin', 'mYtRaNsaCTiOnKEy');
    // Do more CIM stuff here
}
catch (AuthnetCIMException $e)
{
    echo 'There was an error processing the transaction. Here is the error message: ';
    echo $e->__toString();
}

Now that we have an idea of how to use CIM to create profiles and process transactions, let’s put it all together into one script to demonstrate how it all works together. This one has some minor changes and additions that should better demonstrate how to use the AuthnetCIM class and should also make tinkering with this code easier to do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
< ?php
// Include AuthnetCIM class. Nothing works without it!
require('AuthnetCIM.class.php');
 
// Use try/catch so if an exception is thrown we can catch it and figure out what happened
try
{
    // Create AuthnetCIM object. Set third parameter to "true" for developer account
    // or use the built in constant USE_DEVELOPMENT_SERVER for better readability.
    $cim = new AuthnetCIM('myapilogin', 'mYtRaNsaCTiOnKEy', AuthnetCIM::USE_DEVELOPMENT_SERVER);
 
    // Step 1: create Customer Profile
    //
    // Create unique fake email address, description, and customer ID
    $email_address = 'user' . time() . '@domain.com';
    $description   = 'Monthly Membership No. ' . md5(uniqid(rand(), true));
    $customer_id   = substr(md5(uniqid(rand(), true)), 16, 16);
 
    // Create the profile
    $cim->setParameter('email', $email_address);
    $cim->setParameter('description', $description);
    $cim->setParameter('merchantCustomerId', $customer_id);
    $cim->createCustomerProfile();
 
    // Get the profile ID returned from the request
    if ($cim->isSuccessful())
    {
        $profile_id = $cim->getProfileID();
    }
 
    // Print the results of the request
    echo '<b>createCustomerProfileRequest Response Summary:</b> ' . $cim->getResponseSummary() . '<br />';
    echo '<b>Profile ID:</b> ' . $profile_id . '<br /><br />';
 
    // Step 2: create Payment Profile
    //
    // Create fake user billing information
    $b_first_name   = 'John';
    $b_last_name    = 'Conde';
    $b_address      = '123 Main Street';
    $b_city         = 'Townsville';
    $b_state        = 'NJ';
    $b_zip          = '12345';
    $b_country      = 'US';
    $b_phone_number = '800-555-1234';
    $b_fax_number   = '800-555-2345';
    $credit_card    = '4111111111111111';
    $expiration     = (date("Y") + 1) . '-12';
 
    // Create the Payment Profile
    $cim->setParameter('customerProfileId', $profile_id);
    $cim->setParameter('billToFirstName', $b_first_name);
    $cim->setParameter('billToLastName', $b_last_name);
    $cim->setParameter('billToAddress', $b_address);
    $cim->setParameter('billToCity', $b_city);
    $cim->setParameter('billToState', $b_state);
    $cim->setParameter('billToZip', $b_zip);
    $cim->setParameter('billToCountry', $b_country);
    $cim->setParameter('billToPhoneNumber', $b_phone_number);
    $cim->setParameter('billToFaxNumber', $b_fax_number);
    $cim->setParameter('cardNumber', $credit_card);
    $cim->setParameter('expirationDate', $expiration);
    $cim->createCustomerPaymentProfile();
 
    // Get the payment profile ID returned from the request
    if ($cim->isSuccessful())
    {
        $payment_profile_id = $cim->getPaymentProfileId();
    }
 
    // Print the results of the request
    echo '<b>createCustomerPaymentProfileRequest Response Summary:</b> ' . $cim->getResponseSummary() . '<br />';
    echo '<b>Payment Profile ID:</b> ' . $payment_profile_id . '<br /><br />';
 
 
    // Step 3: create Shipping Profile
    //
    // Create fake user shipping information
    $s_first_name   = 'John';
    $s_last_name    = 'Conde';
    $s_address      = '1001 Other Road';
    $s_city         = 'Townsville';
    $s_state        = 'NJ';
    $s_zip          = '12345';
    $s_country      = 'US';
    $s_phone_number = '800-555-3456';
    $s_fax_number   = '800-555-4567';
 
    // Create the shipping profile
    $cim->setParameter('customerProfileId', $profile_id);
    $cim->setParameter('shipToFirstName', $s_first_name);
    $cim->setParameter('shipToLastName', $s_last_name);
    $cim->setParameter('shipToAddress', $s_address);
    $cim->setParameter('shipToCity', $s_city);
    $cim->setParameter('shipToState', $s_state);
    $cim->setParameter('shipToZip', $s_zip);
    $cim->setParameter('shipToCountry', $s_country);
    $cim->setParameter('shipToPhoneNumber', $s_phone_number);
    $cim->setParameter('shipToFaxNumber', $s_fax_number);
    $cim->createCustomerShippingAddress();
 
    // Get the payment profile ID returned from the request
    if ($cim->isSuccessful())
    {
        $shipping_profile_id = $cim->getCustomerAddressId();
    }
 
    // Print the results of the request
    echo '<b>createCustomerShippingAddressRequest Response Summary:</b> ' . $cim->getResponseSummary() . '<br />';
    echo '<b>Shipping Profile ID:</b> ' . $shipping_profile_id . '<br /><br />';
 
 
    // Step 4: Process a transaction
    //
    // Create fake transaction information
    $purchase_amount = '5.00';
 
    // Process the transaction
    $cim->setParameter('amount', $purchase_amount);
    $cim->setParameter('customerProfileId', $profile_id);
    $cim->setParameter('customerPaymentProfileId', $payment_profile_id);
    $cim->setParameter('customerShippingAddressId', $shipping_profile_id);
    $cim->setParameter('cardCode', '123');
    $cim->setLineItem('12', 'test item', 'it lets you test stuff', '1', '1.00');
    $cim->createCustomerProfileTransaction();
 
    // Get the payment profile ID returned from the request
    if ($cim->isSuccessful())
    {
        $approval_code = $cim->getAuthCode();
    }
 
    // Print the results of the request
    echo '<b>createCustomerProfileTransactionRequest Response Summary:</b> ' . $cim->getResponseSummary() . '<br />';
    echo '<b>Approval code:</b> ' . $approval_code;
}
catch (AuthnetCIMException $e)
{
    echo $e;
    echo $cim;
}
?>

Obviously this code is just one part of a larger system of managing user data. But this should make interacting with the Authorize.Net CIM API much easier to do allowing you to focus more on your user experience then learning new APIs.

Related Posts:

Tags: ,

February 8th, 2010 at 12:18 pm | Posted in Programming
BlinkList del.icio.us digg Furl linkaGoGo Newsvine reddit Shadows Simpy Shinn Spurl.net Stumbleupon Tailrank Yahoo! My Web

11 Responses to “Tutorial: Integrate the Authorize.Net CIM API with PHP”

  1. Chad Says:

    I really like the class you created for CIM Authorize.net managment. It is better designed than another one that I found on the web. I built a nice solution with your class and it was working great when I went to the test server, but when I switched it to production (and changed nothing else) I get this error:

    Notice: AuthnetCIM::setParameter() parameter “value” is empty or missing. in /home2/freecig/public_html/admin/AuthnetCIM.class.php on line 629

    Notice: AuthnetCIM::setParameter() parameter “value” is empty or missing. in /home2/freecig/public_html/admin/AuthnetCIM.class.php on line 629

    I spent a good day trying to debug it. I found that even if I hard-code the value passed into

    Warning: SimpleXMLElement::__construct() [simplexmlelement.--construct]: Entity: line 1: parser error : Start tag expected, ‘__construct(‘XMLSchema-insta…’) #1 /home2/freecig/public_html/admin/AuthnetCIM.class.php(123): AuthnetCIM->parseResults() #2 /home2/freecig/public_html/admin/AuthnetCIM.class.php(387): AuthnetCIM->process() #3 /home2/freecig/public_html/admin/process-payment.php(35): AuthnetCIM->createCustomerProfileTransaction() #4 {main} thrown in /home2/freecig/public_html/admin/AuthnetCIM.class.php on line 637

    The problem is in parseResults(). Specifically at this line: $xml = new SimpleXMLElement($response);

    I found that even if I hard-coded the exact same string that was returned when going through the test server and set that for $response and pass it into SimpleXMLElement it blows up with a similar error.

    I would like to use your class but I am stuck. Do you know if the production api handles xml differently? Did you encounter this problem at all?

  2. Johnny Says:

    Chad,

    I’m guessing that the live server is sending back a slightly different response which is causing the XML parser to bork out on us. I made a change that should deal with this if that is indeed the case. Download a new copy of the class and let me know how it goes.

    John

  3. Bookmarks for April 15th from 14:55 to 14:55 | Buddy's Blog Says:

    [...] Tutorial: Integrate the Authorize.Net CIM API with PHP :: John Conde .net – Share and Enjoy: [...]

  4. Rasmus Schultz Says:

    I don’t think the updateCustomerPaymentProfile() method will work – you left out the customerPaymentProfileId in this function.

    Since you can have multiple payment profiles per customer, it can’t know which one it’s supposed to update.

    In the example shown for this request in the documentation, they do include it, and I’m sure it must be required? Although, in the documentation itself, they forgot it – but I don’t think that means it’s going to work…

  5. Johnny Says:

    Rasmus,

    Good catch. I’ve updated the code to correct this. Thanks for reporting it!

  6. Rasmus Schultz Says:

    And another one – in deleteCustomerPaymentProfile() you’re passing the customerProfileId as the customerPaymentProfileId:

    ‘.$this->params['customerProfileId'].’

    This should read:

    ‘.$this->params['customerPaymentProfileId'].’

    I’m starting to think this library was never tested before release?

  7. Rasmus Schultz Says:

    The markup got stripped in the comment above – that’s line 411, and it needs to read $this->params['customerPaymentProfileId'], not $this->params['customerProfileId']

  8. Johnny Says:

    Shame on me. I fixed that on my local copy but never ported it to the copy I have here. Good catch and once again for the bug reports!

  9. Leighton Whiting Says:

    Thanks John for the great tutorial and class, you’ve made my life much easier :)

  10. Leighton Whiting Says:

    Just thought I’d share that I ended up removing the CVV part of the class, because storing that information in the database is against PCI rules and I had to do automated payments using Cron, so I couldn’t ask the user to enter their CVV each time they want to make a payment. CIM doesn’t require the CVV, it is an optional parameter.

    Sincerely,
    Leighton Whiting

  11. Authorize.net newbie Says:

    Hi John,

    Line 374-378 reads:

    if (isset($this->params['orderInvoiceNumber']))
    {
    $this->xml .= ‘
    ‘. $this->params['approvalCode'].”;
    }

    I think it should check for approval code instead of orderInvoiceNumber like:

    if (isset($this->params['approvalCode']))
    {
    $this->xml .= ‘
    ‘. $this->params['approvalCode'].”;
    }

    Also, where can I download your latest code for this class? I can still see those bugs mentioned above in the code I downloaded 10 minutes ago.

    Thanks for the class, its such a time saver!

    -Kshama

Leave a Reply