Getting Started with Payment Gateway Integration

Getting a payment app up and running means being able to handle at least two different kinds of integration: First, you need to know how to integrate the necessary hardware (i.e., the card reader plus whatever it’s plugged into); then you need to know how to integrate with a payment “back end,” such as an online payment gateway (the party that “okays” the transaction and processes it for settlement).

In previous posts, I’ve talked a lot about the hardware integration piece of this puzzle, which turns out to be not so terribly difficult, because with ID TECH card readers, you can use our Universal SDK to talk to devices from a high-level language environment, or you can do a pure-JavaScript solution, if you’re willing to enlist Node JS in your architecture. Either way, talking to ID TECH devices isn’t really a very big deal.

But the question remains: After you get the credit card reader to read the card’s chip or stripe, how do you convert that info into an approved transaction?

Presumably, you already know which credit card processor will be handling your requests. So the problem really comes down to finding out what kind of SDK support your processor or gateway offers, for fulfilling online requests.

Most gateways or processors have a developer’s program, or development portal online, where you can obtain SDKs for building payment apps. The SDKs will generally let you build a combination of front-end and back-end components for accessing the processor’s payment APIs. The payment APIs, in turn, support submission of magstripe data and/or ICC (chip card) data, over the wire, to a back end processor, for the purpose of obtaining realtime authorization.

Payment authorization is actually just one of several types of online request you’ll probably need to support. Some of the other request types are shown in the table below.

Request Type

Description

Auth

Request authorization for payment

Conf

Confirm a previous authorization request

Offline

Settle an offline-EMV transaction

PreAuth

Confirm card details are valid, using a small transaction amount

Refund

Refund a previously settled transaction

Test

Test connectivity to the processor

VoiceReferralNotification

Notify the processor of the result of a voice referral request

Void

Used to void a transaction that has not been settled

If you study the SDK docs for your payment processor, you’ll notice that quite a number of different result codes and/or error codes apply to each transaction type. How do you test against all those possible error types? Answer: Most processors have a scheme wherein the penny amount of a transaction can be set to a special value to trigger a particular error in a testing-sandbox environment. (For example, if the error code for Amount Too Large is 1243, the SDK might let you trigger that specific error by submitting a test transaction in the amount of $12.43.) Check your provider’s SDK docs for details.

Many payment processors have pre-certified (semi-integrated) “in app” solutions that let you route encrypted card data straight to the back end, more or less transparently, keeping your payment app out of “PCI scope,” whereas others assume you will take on “scope” issues yourself, in which case you’ll probably send encrypted card data over the wire to your own server app, behind a firewall, where (with the help of an HSM) you’ll decrypt card data before routing it on to an acquirer or gateway.

AN EXAMPLE

Enough high-level overview. Let’s talk about what it means, in reality, to integrate with a payment back end.

This particular example won’t apply to all cases, obviously (no single example can), but it should give you a bit of the flavor of what you’re likely to encounter when you go to integrate with a back end.

In this case, I was tasked with putting together a “virtual terminal” demo app that sends transaction data to the CreditCall test server to obtain a live authorization for EMV transactions. CreditCall has a back-end server API that can be accessed via HTTPS using their ChipDNA Direct API, which in turn can be “developed against” using an SDK in Java, C++, Perl, or other languages. I chose the Java version.

At the ChipDNA Direct web site, I signed up for a developer account and quickly received (via e-mail) credentials with which to access the CreditCall test server. I also downloaded CreditCall’s Java SDK and started looking at the sample code. I specifically wanted to learn how to submit EMV transactions for authorization. As luck would have it, one of the example code files, ExampleAuthEMV.java, showed just the kind of code I needed.

I set to work writing two Java classes: a servlet class to handle HTTP requests from a browser-based front end, plus a “worker” class to take the browser data (obtained by the servlet) to the CreditCall back end. The former ended up being about 250 lines of Java; the latter, 92 lines.

I am not going to show the code for the servlet class, because it’s pretty much standard Java servlet code, except that it takes TLV values (submitted as form field values, using AJAX) and puts them into a java.util.Hashtable object at runtime. That Hashtable is then handed to my worker class’s static authorize() method. The worker class uses the CreditCall ChipDNA Direct SDK helper (library) classes to create a com.creditcall.Request object, which then gets handed to a Client object, which in turn calls the CreditCall server. Here’s the code:

package com.idtech.server;

import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import com.creditcall.CardEaseXMLCommunicationException;
import com.creditcall.CardEaseXMLRequestException;
import com.creditcall.CardEaseXMLResponseException;
import com.creditcall.Client; 
import com.creditcall.ICCTag;
import com.creditcall.Request;
import com.creditcall.RequestType;
import com.creditcall.Response;

public class Authorizer {
	
	// Note: The values shown below are placeholders only.
	final static String TerminalID = "99999999"; // PUT YOUR ID HERE
	final static String TransactionKey = "689gM8CBE73haZhG"; // PUT YOUR KEY HERE
	
	public static Request getNewRequest( ) {
		
		// Set up the request
		Request request = new Request();

		request.setSoftwareName("IDTech Virtual Terminal");
		request.setSoftwareVersion("Version 0.9");
		request.setTerminalID( TerminalID );
		request.setTransactionKey( TransactionKey );

		// Set up the request detail
		request.setRequestType(RequestType.Auth);
		request.setAmount("100"); // default, will be overwritten
		
		return request;
	}
	
	public static final Response authorize( Hashtable<String,String> TLVs ) throws IOException {
		
		Request request = getNewRequest( );
			
		Enumeration<String> names = TLVs.keys();
		while(names.hasMoreElements()) {
			
		      String tag = (String) names.nextElement();
		      String value = TLVs.get(tag);	      
		      
		      // Make sure amount in 9F02 agrees with
		      // request.setAmount() and vice versa
		      if ( tag.indexOf("9F02") == 0 ) {
		    	 
		    	  String val = value.substring(4);
		    	  while ( val.substring(0,1) == "0" )
		    		  val = val.substring(1);
		    	  if ( val == "" )
		    		  val = "0"; 
		    	  request.setAmount( val );
		      }
		      
		      // Add tag to the request
		      request.addICCTag(new ICCTag("0x"+tag.toLowerCase(), value ));
		}

		// Set up the client
		Client client = new Client();
		client.setRequest(request);

		try {
			client.addServerURL("https://test.cardeasexml.com/generic.cex", 45000);

			// Process the request
			client.processRequest();

		} 	
		catch (final CardEaseXMLCommunicationException e) {
			// There is something wrong with communication
			e.printStackTrace();
		} catch (final CardEaseXMLRequestException e) {
			// There is something wrong with the request
			e.printStackTrace();
		} catch (final CardEaseXMLResponseException e) {
			// There is something wrong with the response
			e.printStackTrace();
		}
		
		// Get the response
		Response response = client.getResponse();
		System.out.println(response);
		
		return response;		
	}
}

This code is so short and self-explanatory, it hardly warrants further comment. The neat thing about it is that the CreditCall Request and Client classes take care of creating the necessary XML documents that ultimately get sent to CreditCall’s server. As a developer, you never have to see, touch, parse, or worry about raw XML yourself (just as Nature intended).

Note that you need to provide your test-account credentials in Lines 18 and 19. (The credentials shown above are fake. Don’t try to use the code verbatim!) Line 69 is where you set the URL to the CreditCall endpoint. Line 72 issues the actual outbound HTTPS call.

The CreditCall server is not particularly fussy with regard to which TLV tags you send in your transaction data, as along as you include the ones that contain essential card data (so for example: tags 5A and 57, for contact EMV; tag 56 for contactless; plus 9F26 and 9F27, containing cryptogram info). In response to your EMV data, the CreditCall server will generally return TLVs for tags 8A, 89, and 91, and optionally 71 or 72 (if scripts need to be conveyed to the chip card). The auth code you want is in tag 89.

Through trial and error, I learned that the CreditCall server app is not quick to decline a transaction merely because the card presents an AAC cryptogram. (You can determine the type of cryptogram by inspecting the top bits of tag 9F27. Zeros mean AAC, or Decline.) This is not unexpected, though, because the card’s advice is merely that: advice. The final thumbs-up or thumbs-down for an EMV transaction is generally up to the acquirer. The card can be (and often is) overruled.

As you can see, you learn a lot of interesting details about EMV by playing around with this stuff. Nothing beats doing a live authorization, when it comes to verifying payment-app code!

Looking for more advice on EMV transactions? Check out our Development Home page on the ID TECH Knowledge Base. Download our EMV development white paper. Or call one of our experts toll-free to get started with an eval kit:

Toll Free Number
1-800-984-1010