1 package Business::OnlinePayment::AuthorizeNet;
5 use Business::OnlinePayment;
6 use Net::SSLeay qw/make_form post_https make_headers/;
8 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
12 @ISA = qw(Exporter Business::OnlinePayment);
20 $self->server('secure.authorize.net');
22 $self->path('/gateway/transact.dll');
24 $self->build_subs(qw( order_number md5 avs_code cvv2_response
32 my %content = $self->content();
35 my %actions = ('normal authorization' => 'AUTH_CAPTURE',
36 'authorization only' => 'AUTH_ONLY',
38 'post authorization' => 'PRIOR_AUTH_CAPTURE',
41 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
44 my %types = ('visa' => 'CC',
46 'american express' => 'CC',
50 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
51 $self->transaction_type($content{'type'});
54 my %account_types = ('personal checking' => 'CHECKING',
55 'personal savings' => 'SAVINGS',
56 'business checking' => 'CHECKING',
57 'business savings' => 'SAVINGS',
59 $content{'account_type'} = $account_types{lc($content{'account_type'})}
60 || $content{'account_type'};
62 $content{'referer'} = defined( $content{'referer'} )
63 ? make_headers( 'Referer' => $content{'referer'} )
66 if (length $content{'password'} == 15) {
67 $content{'transaction_key'} = delete $content{'password'};
70 # stuff it back into %content
71 $self->content(%content);
77 my %content = $self->content();
79 $content{$map{$_}} = $content{$_};
81 $self->content(%content);
85 my($self,@fields) = @_;
87 my %content = $self->content();
89 foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
100 password => 'x_Password',
101 transaction_key => 'x_Tran_Key',
103 description => 'x_Description',
104 amount => 'x_Amount',
105 currency => 'x_Currency_Code',
106 invoice_number => 'x_Invoice_Num',
107 order_number => 'x_Trans_ID',
108 auth_code => 'x_Auth_Code',
109 customer_id => 'x_Cust_ID',
110 customer_ip => 'x_Customer_IP',
111 last_name => 'x_Last_Name',
112 first_name => 'x_First_Name',
113 company => 'x_Company',
114 address => 'x_Address',
118 country => 'x_Country',
119 ship_last_name => 'x_Ship_To_Last_Name',
120 ship_first_name => 'x_Ship_To_First_Name',
121 ship_company => 'x_Ship_To_Company',
122 ship_address => 'x_Ship_To_Address',
123 ship_city => 'x_Ship_To_City',
124 ship_state => 'x_Ship_To_State',
125 ship_zip => 'x_Ship_To_Zip',
126 ship_country => 'x_Ship_To_Country',
130 email_customer => 'x_Email_Customer',
131 card_number => 'x_Card_Num',
132 expiration => 'x_Exp_Date',
133 cvv2 => 'x_Card_Code',
134 check_type => 'x_Echeck_Type',
135 account_name => 'x_Bank_Acct_Name',
136 account_number => 'x_Bank_Acct_Num',
137 account_type => 'x_Bank_Acct_Type',
138 bank_name => 'x_Bank_Name',
139 routing_code => 'x_Bank_ABA_Code',
140 customer_org => 'x_Customer_Organization_Type',
141 customer_ssn => 'x_Customer_Tax_ID',
142 license_num => 'x_Drivers_License_Num',
143 license_state => 'x_Drivers_License_State',
144 license_dob => 'x_Drivers_License_DOB',
145 recurring_billing => 'x_Recurring_Billing',
148 my $auth_type = $self->{_content}->{transaction_key}
152 my @required_fields = ( qw(type action login), $auth_type );
154 unless ( $self->{_content}->{action} eq 'VOID' ) {
156 if ($self->transaction_type() eq "ECHECK") {
158 push @required_fields, qw(
159 amount routing_code account_number account_type bank_name
163 if (defined $self->{_content}->{customer_org} and
164 length $self->{_content}->{customer_org}
166 push @required_fields, qw( customer_org customer_ssn );
168 push @required_fields, qw(license_num license_state license_dob);
171 } elsif ($self->transaction_type() eq 'CC' ) {
173 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
174 if ( $self->{_content}->{order_number} ) {
175 push @required_fields, qw( amount order_number );
177 push @required_fields, qw( amount card_number expiration );
179 } elsif ( $self->{_content}->{action} eq 'CREDIT' ) {
180 push @required_fields, qw( amount order_number card_number );
182 push @required_fields, qw(
183 amount last_name first_name card_number expiration
187 Carp::croak( "AuthorizeNet can't handle transaction type: ".
188 $self->transaction_type() );
193 $self->required_fields(@required_fields);
195 my %post_data = $self->get_fields(qw/
196 x_Login x_Password x_Tran_Key x_Invoice_Num
197 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
198 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
199 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
200 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
201 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
202 x_Last_Name x_First_Name x_Company
203 x_Address x_City x_State x_Zip
205 x_Ship_To_Last_Name x_Ship_To_First_Name x_Ship_To_Company
206 x_Ship_To_Address x_Ship_To_City x_Ship_To_State x_Ship_To_Zip
208 x_Phone x_Fax x_Email x_Email_Customer x_Country
209 x_Currency_Code x_Trans_ID/);
211 $post_data{'x_Test_Request'} = $self->test_transaction() ? 'TRUE' : 'FALSE';
213 #deal with perl-style bool
214 if ( $post_data{'x_Email_Customer'}
215 && $post_data{'x_Email_Customer'} !~ /^FALSE$/i ) {
216 $post_data{'x_Email_Customer'} = 'TRUE';
218 $post_data{'x_Email_Customer'} = 'FALSE';
221 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
222 $post_data{'x_delim_char'} = ',';
223 $post_data{'x_encap_char'} = '"';
224 $post_data{'x_ADC_URL'} = 'FALSE';
225 $post_data{'x_Version'} = '3.1';
227 my $pd = make_form(%post_data);
228 my $s = $self->server();
229 my $p = $self->port();
230 my $t = $self->path();
231 my $r = $self->{_content}->{referer};
232 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
233 #escape NULL (binary 0x00) values
234 $page =~ s/\x00/\^0/g;
236 #trim 'ip_addr="1.2.3.4"' added by eProcessingNetwork Authorize.Net compat
237 $page =~ s/,ip_addr="[\d\.]+"$//;
239 my $csv = new Text::CSV_XS({ binary=>1, escape_char=>'' });
241 my @col = $csv->fields();
243 $self->server_response($page);
244 $self->avs_code($col[5]);
245 $self->order_number($col[6]);
246 $self->md5($col[37]);
247 $self->cvv2_response($col[38]);
248 $self->cavv_response($col[39]);
250 if($col[0] eq "1" ) { # Authorized/Pending/Test
251 $self->is_success(1);
252 $self->result_code($col[0]);
253 if ($col[4] =~ /^(.*)\s+(\d+)$/) { #eProcessingNetwork extra bits..
254 $self->authorization($2);
256 $self->authorization($col[4]);
259 $self->is_success(0);
260 $self->result_code($col[2]);
261 $self->error_message($col[3]);
262 unless ( $self->result_code() ) { #additional logging information
263 #$page =~ s/\x00/\^0/g;
264 $self->error_message($col[3].
265 " DEBUG: No x_response_code from server, ".
266 "(HTTPS response: $server_response) ".
268 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
269 "(Raw HTTPS content: $page)"
280 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
284 use Business::OnlinePayment;
287 # One step transaction, the simple case.
290 my $tx = new Business::OnlinePayment("AuthorizeNet");
293 login => 'testdrive',
294 password => '', #password or transaction key
295 action => 'Normal Authorization',
296 description => 'Business::OnlinePayment test',
298 invoice_number => '100100',
299 customer_id => 'jsk',
300 first_name => 'Jason',
301 last_name => 'Kohles',
302 address => '123 Anystreet',
306 card_number => '4007000000027',
307 expiration => '09/02',
308 cvv2 => '1234', #optional
309 referer => 'http://valid.referer.url/',
313 if($tx->is_success()) {
314 print "Card processed successfully: ".$tx->authorization."\n";
316 print "Card was rejected: ".$tx->error_message."\n";
320 # Two step transaction, authorization and capture.
321 # If you don't need to review order before capture, you can
322 # process in one step as above.
325 my $tx = new Business::OnlinePayment("AuthorizeNet");
328 login => 'testdrive',
329 password => '', #password or transaction key
330 action => 'Authorization Only',
331 description => 'Business::OnlinePayment test',
333 invoice_number => '100100',
334 customer_id => 'jsk',
335 first_name => 'Jason',
336 last_name => 'Kohles',
337 address => '123 Anystreet',
341 card_number => '4007000000027',
342 expiration => '09/02',
343 cvv2 => '1234', #optional
344 referer => 'http://valid.referer.url/',
348 if($tx->is_success()) {
349 # get information about authorization
350 $authorization = $tx->authorization
351 $ordernum = $tx->order_number;
352 $avs_code = $tx->avs_code; # AVS Response Code
353 $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
354 $cavv_response = $tx->cavv_response; # Cardholder Authentication
355 # Verification Value (CAVV) Response
358 # now capture transaction
359 my $capture = new Business::OnlinePayment("AuthorizeNet");
363 action => 'Post Authorization',
365 password => 'YOURPASSWORD',
366 order_number => $ordernum,
372 if($capture->is_success()) {
373 print "Card captured successfully: ".$capture->authorization."\n";
375 print "Card was rejected: ".$capture->error_message."\n";
379 print "Card was rejected: ".$tx->error_message."\n";
382 =head1 SUPPORTED TRANSACTION TYPES
384 =head2 CC, Visa, MasterCard, American Express, Discover
386 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
390 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
394 For detailed information see L<Business::OnlinePayment>.
396 =head1 METHODS AND FUNCTIONS
398 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
402 Returns the response reason code (this is different than the response code).
406 Returns the response reason text.
408 =head2 server_response
410 Returns the complete response from the server.
414 Unlike Business::OnlinePayment or pre-3.0 verisons of
415 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
418 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
419 Integration Method (AIM) (formerly known as ADC direct response)", sending a
420 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
421 referrer "security" is not necessary. In your Authorize.Net interface at
422 https://secure.authorize.net/ make sure the list of allowable referers is
423 blank. Alternatively, set the B<referer> field in the transaction content.
425 To settle an authorization-only transaction (where you set action to
426 'Authorization Only'), submit the nine-digit transaction id code in
427 the field "order_number" with the action set to "Post Authorization".
428 You can get the transaction id from the authorization by calling the
429 order_number method on the object returned from the authorization.
430 You must also submit the amount field with a value less than or equal
431 to the amount specified in the original authorization.
433 Recently (February 2002), Authorize.Net has turned address
434 verification on by default for all merchants. If you do not have
435 valid address information for your customer (such as in an IVR
436 application), you must disable address verification in the Merchant
437 Menu page at https://secure.authorize.net/ so that the transactions
438 aren't denied due to a lack of address information.
442 This module implements Authorize.Net's API verison 3.1 using the Advanced
443 Integration Method (AIM), formerly known as ADC Direct Response. See
444 http://www.authorize.net/support/AIM_guide.pdf for details.
448 Jason Kohles, jason@mediabang.com
450 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
451 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
454 Jason Spence <jspence@lightconsulting.com> contributed support for separate
455 Authorization Only and Post Authorization steps and wrote some docs.
456 OST <services@ostel.com> paid for it.
458 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
460 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
462 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
464 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
465 card-less post authorizations.
467 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
468 key" authentication as well support for the recurring_billing flag and the md5
469 method that returns the MD5 hash which is returned by the gateway.
471 Steve Simitzis contributed a patch for better compatibility with
472 eProcessingNetwork's AuthorizeNet compatability mode.
476 perl(1). L<Business::OnlinePayment>.