# Direct Card API
# General Overview
GoDaddy Poynt Direct Card API is a feature that allows reading non-payment cards using the card reader on GoDaddy Poynt terminals. This article will cover the steps required to integrate with the functionality.
# Prerequisites
Access to an unlocked GoDaddy Poynt Smart Terminal with the developer mode enabled
Access to Android Studio
# Configuration
Include Poynt SDK in your android project
implementation 'co.poynt.api:android-api-model:1.2.140'
implementation 'co.poynt.android.sdk:poynt-sdk:1.2.42'
TIP
If you wish to review the latest SDK and API versions, please refer to SDK Versions
::: details Cards Supported Currently, the interface supports cards with the protocols listed below:
- SLE 442
- SLE 428
- EMV L1 Compliant Cards
- ISO 7816-3 :::
# Integrating with SDK
# Interface
The API consist of 3 main operations: connectToCard(), exchangeAPDU() and disconnectFromCard().
WARNING!
Make sure to call disconnectFromCard after you are done reading the card information to put the card reader back in payment card mode. Not doing so can result in transaction failures.
interface IPoyntCardReaderService{
/**
* Initiates the card reader to connect over the specific interface (CT or CL or Both). If a
* card is found on any of the specified interfaces, the reader establishes an L1 connection
* to the card. If a card is not found for the specified duration of time, the command returns
* an apprepriate error code.
*
* @param card read connection options
* @param callback {@link IPoyntConnectToCardListener}
*/
void connectToCard(in ConnectionOptions connectionOptions, IPoyntConnectToCardListener callback);
/**
* Disconnects from the card (CT or CL or both) and powers off corresponding interface.
*
* @param card read connection options
* @param callback {@link IPoyntDisconnectFromCardListener}
*/
void disconnectFromCard(in ConnectionOptions connectionOptions, IPoyntDisconnectFromCardListener callback);
/**
* Checks whether a card is present in the card reader slot or not. This command does not check
* whether a connection to the card has been established or not. It only checks if a card is
* physically inserted in the slot such that the card inserted switch is asserted. It does not
* apply to contactless interface.
*
* @param card read connection options
* @param callback {@link IPoyntCardInsertListener}
*/
void checkIfCardInserted(in ConnectionOptions connectionOptions, IPoyntCardInsertListener callback);
/**
* Send an APDU command to the card and receive the response APDU.
*
* @param apduData containing C-APDU
* @param callback {@link IPoyntAPDUListener}
*/
void exchangeAPDU(in APDUData apduData, IPoyntExchangeAPDUListener callback);
/**
* Abort any pending connect or wait for card removal operations.
*
*/
void abort();
/**
* Send a list of APDU commands to the card and receive the response APDU.
*
* @param apduData containing list of C-APDU
* @param callback {@link IPoyntAPDUListListener}
*/
void exchangeAPDUList(in List<APDUData> apduData, IPoyntExchangeAPDUListListener callback);
}
# Binding to the service
..
..
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
cardReaderService = IPoyntCardReaderService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// service is disconnected
}
};
protected void onResume() {
super.onResume();
// Bind to service
bindService(Intents.getComponentIntent(Intents.COMPONENT_POYNT_CARD_READER_SERVICE),
serviceConnection, BIND_AUTO_CREATE);
}
protected void onPause() {
super.onPause();
// Make sure you unbind from service to prevent memory leaks
unbindService(serviceConnection);
}
..
..
# Checking Card Presence
The card reader service API allows checking for card presence, the API returns the result as a callback.
ConnectionOptions connectionOptions = new ConnectionOptions();
// select the interface to check, can be one of EMV, GSM, SLE
connectionOptions.setContactInterface(ConnectionOptions.ContactInterfaceType.GSM);
connectionOptions.setTimeout(60);
try {
cardReaderService.checkIfCardInserted(connectionOptions,
new IPoyntCardInsertListener.Stub() {
@Override
public void onCardFound() throws RemoteException {
// code to handle card found case
}
@Override
public void onCardNotFound() throws RemoteException {
// code to handle card not found
}
@Override
public void onError(PoyntError poyntError) throws RemoteException {
// error occured while checking for card presence, check the error message
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
# Connecting to the Card
Once the card is inserted, connect to the card to verify the connection.
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.setContactInterface(ConnectionOptions.ContactInterfaceType.GSM);
connectionOptions.setTimeout(60);
try {
cardReaderService.connectToCard(connectionOptions,
new IPoyntConnectToCardListener.Stub() {
@Override
public void onSuccess(ConnectionResult connectionResult) throws RemoteException {
// code to handle card connected case
}
@Override
public void onError(PoyntError poyntError) throws RemoteException {
// code to hande error case
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
# Reading Card Data
The card reader is ready for APDU commands once the card is connected, the APDU commands can be sent one at a time or as a list which will be executed in order.
# APDU format
APDU is of the following format
|CASE CLS INS P1 P2 *Lc *Data Le | (* optional)
Sample APDU Commands
// Select MasterFile
APDU: 04 A0 A4 00 00 02 3F00 00
// Get Response of MasterFile
APDU: 02 A0 C0 00 00 00
// Select GSM Directory
APDU: 04 A0 A4 00 00 02 7F20 00
// Select IMSI
APDU: 04 A0 A4 00 00 02 6F07 00
// Get Response of Select IMSI
APDU: 02 A0 C0 00 00 00
// Read Binary IMSI
APDU: 02 A0 B0 00 00 09
# Sending a single APDU command
APDUData apduData = new APDUData();
apduData.setContactInterface(APDUData.ContactInterfaceType.GSM);
apduData.setTimeout(60);
apduData.setCommandAPDU("<YOUR APDU COMMAND>");
try {
cardReaderService.exchangeAPDU(apduData,
new IPoyntExchangeAPDUListener.Stub() {
@Override
public void onSuccess(String rAPDU) throws RemoteException {
// code to handle APDU response
}
@Override
public void onError(PoyntError poyntError) throws RemoteException {
// code to handle APDU command error
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
# Sending multiple APDU commands at once
// first command
APDUData apduData = new APDUData();
apduData.setContactInterface(APDUData.ContactInterfaceType.EMV);
apduData.setTimeout(60);
apduData.setCommandAPDU("<APDU_1>");
// second command
APDUData apduData2 = new APDUData();
apduData2.setContactInterface(APDUData.ContactInterfaceType.EMV);
apduData2.setTimeout(60);
apduData2.setCommandAPDU("<APDU_2>");
ArrayList<APDUData> apdus = new ArrayList<>();
apdus.add(apduData);
apdus.add(apduData2);
try {
cardReaderService.exchangeAPDUList(apdus,
new IPoyntExchangeAPDUListListener.Stub() {
@Override
public void onResult(List<String> list, PoyntError poyntError) throws RemoteException {
if (poyntError != null) {
// error occurred
} else {
// APDU response is in the same order as the commands sent
}
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
# Disconnecting from the card
Disconnect from the card and prompt the user to remove the card to make sure the card reader is ready for the next transaction.
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.setContactInterface(ConnectionOptions.ContactInterfaceType.GSM);
connectionOptions.setTimeout(60);
try {
cardReaderService.disconnectFromCard(connectionOptions,
new IPoyntDisconnectFromCardListener.Stub() {
@Override
public void onDisconnect() throws RemoteException {
// code to handle card disconnected
}
@Override
public void onError(PoyntError poyntError) throws RemoteException {
// handle error
}
});
} catch (RemoteException e) {
e.printStackTrace();
}