Skip to main content

Tap to Pay Android SDK

Accept contactless payments on your Android device with Dojo's Tap to Pay Android SDK.

Overview

note

The code samples in this document use kotlin.

Dojo's Tap to Pay Android SDK (TaP for short) allows customers to take contactless payments using the built-in NFC capabilities included in modern Android devices.

NFC allows users to process mobile point of sale (MPos) transactions on their Android device, and receive in-person contactless payments from physical payment cards and other mobile devices.

This SDK is a collection of intent-based messages. for use with an MPos (Mobile Point of Sale). This can be a smartphone, tablet, or other dedicated wireless device that performs the functions of a cash register or POS terminal.

Intent-based messaging is one of the Inter-Process-Communication (IPC) mechanisms that allow Android components to communicate with one another. User-defined intent messages with optional payloads are passed between processes (for example, apps and Activities) and are be parsed by the receiving component and acted upon.

Compatibility

The Tap to Pay Android SDK is compatible with:

To check if you have activated contactless payments in an Android device, navigate to:

  • Settings > Connections > NFC and Contactless Payments.

If searching NFC in the device settings returns no results, then the device is not compatible with TaP.

Intent sequence

Click one of the intent endpoints in the sequence below to jump to the relevant section.

Format

Intents and extras are written as literal string values, but payload data types can be formatted as string, boolean, or integer.

mobile-sdk/android/tap-to-pay/kotlin/format.kts
loading...

Additional flags

Intents must be created using the SingleTop flag. This means if, for example, a sale request is sent when an identical sale is already at the top of the stack, the system will reuse that existing instance instead of creating a new one.

mobile-sdk/android/tap-to-pay/kotlin/additional-flags.kts
loading...

Initialize

Before defining any sale, refund, or split bill and gratuity logic, the first step is to initialize and provision the TaP SDK.

Request message

Begin the initialization and provisioning process:

val intent = Intent("com.dojo.action.INIT")

TaP provisioning may take up to two minutes to complete.

Prerequisites

Should these checks fail, TaP will not be able to provision.

TaP Action

Initialization is currently a UI-interactive process in TaP, requiring user input to enter the activation code and complete the device setup procedure. In future releases, this third party driven initialization will become a silent background process in TaP, with no UI interaction required. Any required setup data would be passed as a payload within the intent message.

Response

TaP will return its response in the onActivityResult API call of the calling activity:

  • An INIT_COMPLETE response is returned to indicate the status of the initialization.
  • The INIT_RESULT and INIT_RESULT_DETAIL extra fields reflect the initialization status.
    • INIT_RESULT returns a boolean value of true if it is successful and false if it is not.
    • The INIT_RESULT_DETAIL value will be either OK if initialization completes successfully or COMPLETED if it was already initialised before the call was made.
  • If there are any problems an error code will be provided as a string.

This message returns TaP initialization status information to the POS:

mobile-sdk/android/tap-to-pay/kotlin/initialize-response.kts
loading...

Required POS Action

In the onActivityResult Activity callback:

val initResult = data?.getBooleanExtra("com.dojo.extra.INIT_RESULT")
val initResultDetail = data?.getStringExtra("com.dojo.extra.INIT_RESULT_DETAIL")

The POS should parse this message to determine whether the TaP initialization succeeded or failed by parsing the INIT_RESULT boolean. Further information on the failure status will be available in the INIT_RESULT_DETAIL string.

Error codes include:

  • E1 - a payment session failed to start.
  • A10 - a provisioning error occurred.
  • T1 - a timeout caused the provisioning to be cancelled.

The POS app should respond to the messages using one of the following approaches:

  • No action required in the event of a successful device initialization.
  • Re-trying the initialization.
  • Notifying the user of a technical fault after multiple retries.

Sale

Request message

This message is to be used by the POS to request TaP to begin a contactless transaction.

Sender example code:

mobile-sdk/android/tap-to-pay/kotlin/sale-request.kts
loading...

Prerequisites

TaP must have been previously provisioned using INIT in order for this request to succeed.

TaP Action

On receiving the request, TaP will begin a transaction, display the contactless acceptance screen, and wait for the presentation of a contactless EMV card.

Response

The user should present a card to the device for contactless payment. TaP will then process the transaction, contact the acquiring bank for authorization, then show the result to the user.

Should the transaction fail, the reason will be displayed to the user (for example, card declined or card expired). These status codes will be returned to the POS in the response message.

This message returns transaction status and payment data to the POS.

Sender example (TaP):

mobile-sdk/android/tap-to-pay/kotlin/sale-response.kts
loading...

Expected POS Action

The POS should parse this message to determine whether the transaction succeeded or failed by parsing the TRX_RESULT Boolean and TRX_RESULT_DETAIL String.

OnActivityResult example:

mobile-sdk/android/tap-to-pay/kotlin/sale-activity-message.kts
loading...

Refund

Request message

This message is to be used by the POS to request TaP to begin a contactless refund transaction.

Sender example code:

mobile-sdk/android/tap-to-pay/kotlin/refund-request.kts
loading...

Prerequisites

TaP must have been previously provisioned using INIT in order for this request to succeed.

TaP Action

On receiving the request, TaP will begin a transaction, display the contactless acceptance screen, and wait for the presentation of a contactless EMV card.

The user should present a card to the device for contactless payment. TaP will then process the refund transaction, contacting the acquiring bank for authorization and show the result to the user.

Response

This message returns transaction status and payment data to the POS.

Should the transaction fail, the reason will be displayed to the user (for example, card declined or card expired). These status codes will be returned to the POS in the response message.

Sender example (TaP):

mobile-sdk/android/tap-to-pay/kotlin/refund-response.kts
loading...
Key (literal string)ValueType
com.dojo.extra.REFUND_STATUSNOT_PROVISIONED / OKString
com.dojo.extra.BASE_AMOUNTBase transaction amountInteger
com.dojo.extra.TRANSACTION_RESULTAUTHORISED / CANCELLED / DECLINED / FAILEDString
com.dojo.extra.AUTH_CODETx Authorization CodeString
com.dojo.extra.PAYMENT_METHODContactlessString
com.dojo.extra.CARDHOLDER_VERIFICATION_METHODContactless/PINString
com.dojo.extra.CARD_SCHEMEMastercard/Visa/Amex/DiscoverString
com.dojo.extra.CARD_APPLICATION_LABELEMV application labelString
com.dojo.extra.CARD_APPLICATION_IDEMV application IDString
com.dojo.extra.TRANSACTION_IDTaP transaction IDString

Expected POS Action

The POS should parse this message to determine whether the refund succeeded or failed:

  • TRX_RESULT (boolean)
  • TRX_RESULT_DETAIL (string)

OnActivityResult example:

mobile-sdk/android/tap-to-pay/kotlin/refund-activity-message.kts
loading...

Last transaction details

Request message

This message is used by the POS to request details of the last executed transaction. It should be utilized in scenarios where the POS fails to receive a response from the preceding transaction. Example situations include:

  • The TaP app failed to send the response due to an internal failure.
  • The POS app failed during processing the response.
  • The device restarted before the POS could process the response.
val intent = Intent("com.dojo.action.LAST_TX")

Prerequisites

TaP must have been previously provisioned using INIT for this request to succeed.

TaP Action

Upon receiving this message, TaP will return the available details from the last completed transaction, regardless of the transaction outcome (authorized, declined, or failed).

It is not currently possible to request details for a specific transaction.

Response

The LAST_TX_COMPLETE message is returned to the caller in the onActivityResult activity callback handler, containing transaction status information. The field SPLIT_BILL indicates whether the last transaction was split between two or more customers.

Fields default to empty strings where data was not successfully retrieved, for example, where card data could not be fetched successfully. The payload contains the following data:

Key (literal string)ValueType
com.dojo.extra.SPLIT_BILLFalseBoolean
com.dojo.extra.TX_STATUSOKString
com.dojo.extra.BASE_AMOUNTBase transaction amountInteger
com.dojo.extra.GRATUITY_AMOUNTGratuity transaction amountInteger
com.dojo.extra.TRANSACTION_RESULTAUTHORISED / CANCELLED / DECLINED / FAILEDString
com.dojo.extra.AUTH_CODETx Authorization CodeString
com.dojo.extra.PAYMENT_METHODCONTACTLESS / KEYEDString
com.dojo.extra.CARDHOLDER_VERIFICATION_METHODContactless / PINString
com.dojo.extra.CARD_SCHEMEMastercard / Visa / Amex / DiscoverString
com.dojo.extra.CARD_APPLICATION_LABELEMV application labelString
com.dojo.extra.CARD_APPLICATION_IDEMV application IDString
com.dojo.extra.TRANSACTION_IDTaP transaction IDString
mobile-sdk/android/tap-to-pay/kotlin/last-transaction-response.kts
loading...

Split bills and gratuities

At the payment stage, you can split a bill into constituent transactions and then recombine those into a bundle. You can also determine the amount of gratuity using TOTAL_GRATUITY_AMOUNT.

Split bills and gratuities can be enabled by sending a specific request message to TaP:

val intent = Intent("com.dojo.action.ENABLE_SPLIT_BILLS")
intent.putExtra("com.dojo.extra.ENABLE_SPLIT_BILLS", true :Boolean)
intent.putExtra("com.dojo.extra.ENABLE_GRATUITIES", true :Boolean)

Response

This message returns the status of the request to enable split bills and gratuities.

mobile-sdk/android/tap-to-pay/kotlin/bill-gratuity-response.kts
loading...

These are the response schema associated with a bundled collection, as a whole:

Key (literal string)ValueType
com.dojo.extra.PAYMENTS_MADENumber of payments madeInteger
com.dojo.extra.TOTAL_BASE_AMOUNTTotal amount to be paid in penniesInteger
com.dojo.extra.TOTAL_PAID_AMOUNTTotal amount paid in penniesInteger
com.dojo.extra.TOTAL_GRATUITY_AMOUNTTotal gratuity amount paid in penniesString
com.dojo.extra.PAYMENT_KEYSList of payment keysList(String)

The value passed for PAYMENT_KEYS will be a list of strings. These keys are associated with individual transactions inside the split bill bundle.

The details of each transaction can then be extracted as a bundle from the intent response using that key.

Individual bundle item schema

You can extract individual transaction information from a split bill bundle:

mobile-sdk/android/tap-to-pay/kotlin/bundle-item.kts
loading...

These response schema are associated with individual transactions extracted from a bundle:

Key (literal string)ValueType
com.dojo.extra.TX_STATUSNOT_PROVISIONEDOK
com.dojo.extra.BASE_AMOUNTBase transaction amountInteger
com.dojo.extra.GRATUITY_AMOUNTGratuity transaction amountInteger
com.dojo.extra.TRANSACTION_RESULTAUTHORISED / DECLINED / FAILEDString
com.dojo.extra.AUTH_CODETx Authorisation CodeString
com.dojo.extra.PAYMENT_METHODContactlessString
com.dojo.extra.CARDHOLDER_VERIFICATION_METHODContactless/PINString
com.dojo.extra.CARD_SCHEMEMastercard/Visa/Amex/DiscoverString
com.dojo.extra.CARD_APPLICATION_LABELEMV application labelString
com.dojo.extra.CARD_APPLICATION_IDEMV application IDString
com.dojo.extra.TRANSACTION_IDTaP transaction IDString

Expected POS action

The POS should parse this message to determine whether the request succeeded by parsing the ENABLE_SPLIT_BILLS_RESULT and ENABLE_GRATUITIES_RESULT booleans.

OnActivityResult example:

mobile-sdk/android/tap-to-pay/kotlin/split-bill-message.kts
loading...