# 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();
  }
Last Updated: 9/4/2023, 1:28:22 PM