# Direct card API

# Overview

Poynt Direct card API allows reading non payment cards using the card reader on poynt terminals. This tutorial will explain the steps required to integrate.

# Prerequisites

This tutorial assumes you have access to an unlocked Poynt terminal(developer mode) and Android studio.

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

For latest sdk and api versions refer to SDK Versions

Cards supported

The interface supports cards with protocols listed below

  • SLE 442
  • SLE 428
  • EMV L1 Compliant Cards
  • ISO 7816-3

# Integrating with the 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 info 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 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);
  }
  ..
  ..

# Check card presence

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();
  }

# Connect to 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();
  }

# Read 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

# Send 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();
  }

# Send 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();
  }

# Disconnect from card

Disconnect from the card and prompt the user to remove the card to make sure the card reader is ready for 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();
  }

# Frequently Asked Questions

# Can we use this interface to read payment cards?

No. Payment cards are encrypted by the secure module in the card reader, no application has access to the card data in clear text.

# Is there a code sample ready to use?

Yes, refer to this code sample (opens new window)

Last Updated: 10/26/2020, 4:17:58 PM