Tap to Pay on iOS

iOS Deep Linking Integration

Prerequisites

Before you get started with your implementation, read the integration overview to learn about integration and required configuration.

You are onboarded to our sandbox enviroment as a merchant and has a valid TPN.

Setup Testing Environment

Before setting up the testing device

  • Use a separate device for testing.

  • Only use the credentials given to you throughout the testing process.

To get sandbox credentials, contact support@dejavoosystems.com

  • Avoid changing the account during testing.

  • Don't change the device's date and time.

  • These rules apply only to the testing environment, not production.

To Develop iOS Application, Create a new iOS project or use the existing project and configure the below app setup.

Initially, we will use the new TPN. You must accept the Apple Tap-on-Phone Terms and Conditions before proceeding with the Tap-on-Pay transaction.

iosimage-tandc.png

Configure the URL Scheme

Keys demo-AppLink and iPosgo-AppLink are case sensitive.

  1. Demo App Setup

iosimage-1.png

  1. iPosGo! Setup

iosimage-2.png

  1. Configure the SDK

Install the Applications

To install Demo App and iPosGo!! Application via link. I’ll create a diawi Link for testing purposes using this url to obtain the UDID for your device. I can now share the source file of the Demo application so that you can see how it is implemented.

https://get.udid.io/ (opens in a new tab)

TPN Register

TPN register is used to download the parameters to configure the merchant configuration data from the backend application portal.

Input Request Parameters:

FieldTypeDescriptionExample
tpn * string It’s a Unique 12-digit code. This value is unique for each merchant.123456789012
applicationType string The application type is used to identify the application"IPosGo!"
  1. To access the SDK Reader wrapper class, import DeepLinking, and initiate an instance of the class as follows:
import DeepLinking
  1. Create a variable to access the methods
var deepLinkVariable = Wrapper()
  1. Access makeARequestBasedOnTPN() on deepLinkVariable
deepLinkVariable.makeARequestBasedOnTPN(tpnNo: tpn, delegate: self)
  1. Below snippet helps to make a connection between the iPosGo! and Demo App.
func didReceiveResponse(sucess success: URL?) {
  if UIApplication.shared.canOpenURL(success!) {
  UIApplication.shared.open(success!, options: [:]) { result in
    print(result)
    }
  }
  else {
  print("App Not Installed in the Device!")
  }
}

Perform Transactions

This api is used to Demo application to perform the transaction. It supports SALE, REFUND, VOID, PRE-AUTH & TICKET transaction types.

1. SALE, REFUND, PREAUTH

Input Request Parameters:

FieldTypeDescriptionExample
type * string Transaction type [SALE, REFUND, PREAUTH]sale
amount * string Transaction Amount10.00
  1. Access makeARequestBasedOnTransactionTypes() on deepLinkVariable
deepLinkVariable.makeARequestBasedOnTransactionTypes(type: Type, Amount: Amount, delegate: self)  
  1. Below snippet helps to make a sale transaction.
func didReceiveResponse(success: URL?) {
  if UIApplication.shared.canOpenURL(success!) {
    UIApplication.shared.open(success!, options: [:]) { result in
        print(result)
      }
  } 
  else {
    txtResponse.text = ""
    showAlert(alertMessage: "App Not Installed in the Device!")
  }
}

2. VOID, TICKET

Input Request Parameters:

FieldTypeDescriptionExample
type * string Transaction type [VOID, TICKET]ticket
rrn * string Its Unique identifier to track the transaction from TXN response1234567890
  1. Access makeARequestBasedOnTransactionTypes() on deepLinkVariable
deepLinkVariable.makeARequestBasedOnTransactionTypes(type: Type, Amount: rrn, delegate: self)  
  1. Below snippet helps to make a void transaction.
func didReceiveResponse(success: URL?) {
  if UIApplication.shared.canOpenURL(success!) {
    UIApplication.shared.open(success!, options: [:]) { result in
        print(result)
      }
  } 
  else {
    txtResponse.text = ""
    showAlert(alertMessage: "App Not Installed in the Device!")
  }
}

3. BATCH

InputRequest Parameters:

FieldTypeDescriptionExample
type * string Transaction type [BATCH/ SETTLEMENTS]batch
amount string Transaction Amount""
  1. Access makeARequestBasedOnTransactionTypes() on deepLinkVariable
deepLinkVariable.makeARequestBasedOnTransactionTypes(type: Type, Amount :"", delegate: self)  
  1. Below snippet helps to make a batch settlement.
func didReceiveResponse(success: URL?) {
  if UIApplication.shared.canOpenURL(success!) {
    UIApplication.shared.open(success!, options: [:]) { result in
        print(result)
      }
  } 
  else {
    txtResponse.text = ""
    showAlert(alertMessage: "App Not Installed in the Device!")
  }
}

Transaction Response

iPosGo! Call back the result in Demo like this. You can fetch the details.

{
  {  
    [ 
      "Card":  { AID = A000000025010801; Label = AMEX; MaskedPan = 3767522012; }, 
      "BaseAmt": ["Amt": "100", "Label": "Amount"], 
      "TxDetail": {DateNTime = 20240515191215; Tpn = 544424127175; TraceNo = 1; }, 
      "BaseFee": ["Amt": "5", "Label": "BaseFee"], 
      "Tax2": ["Amt": "21", "Label": "Tax2"], 
      "surveyAns": "1", "Currency": "840", 
      "Tip": ["Amt": "20", "Label": "Tip"], 
      "Tax1": ["Amt": "11", "Label": "Tax1"], 
      "Response": { 
        AppCode = AXS802; 
        BatchNo = 63; 
        CardType = CREDIT;
        DTxId = 03430717348412717520240515191215;
        HTxId = 000000321000803; 
        InvoiceNo = 5;
        RespCode = 00; 
        RespMsg = "APPROVAL AXS802 "; 
        Rrn = 413613500098; 
        TxRefNo = 034307173484; 
        }
      ] 
  "Date" : "03.09.2023"
  }
}  

Payment Session Errors

enum PaymentSessionError: String {
    case notAllowed = "Account not allowed."
    case backgroundRequestNotAllowed = "Background request not allowed."
    case unsupported = "Unsupported hardware or a problem with the device"
    case osVersionNotSupported = "Please update your app to the latest iOS version."
    case modelNotSupported = "Current device doesn't support NFC."
    case networkError = "Please check your network settings and try again."
    case networkAuthenticationError = "An authentication error occurred during the server connection."
    case serviceConnectionError = "Internal service is unavailable."
    case notReady = "Please try the session again to resolve the issue."
    case emptyReaderToken = "The token is empty, making it invalid."
    case prepareExpired = "Please reinitiate the session to try again"
    case tokenExpired = "Token Expired."
    case readerMemoryFull = "The card reader is busy."
    case accountNotLinked = "Accept the Terms and Conditions using a valid Apple ID."
    case accountAlreadyLinked = "Terms and Conditions have already been accepted."
    case accountLinkingFailed = "The system couldn't link or relink the merchant using the provided Apple ID."
    case accountLinkingRequiresiCloudSignIn = "Please accept the Terms and Conditions on your device while signed into iCloud"
    case accountLinkingCancelled = "The linking or relinking operation has been canceled."
    case merchantBlocked = "The merchant is blocked"
    case invalidMerchant = "The merchant is invalid or unknown"
    case somethingWentWrong = ""
}

Card Reader Session Errors

enum CardReaderSessionError: String {
  case cardReadFailed = "The reader was unable to read a card"
  case invalidAmount = "Amount must be positive and contain less than 10 digits."
  case invalidCurrencyCode = "Currency code in the request must follow the ISO 4217 standard."
  case nfcDisabled = "The user needs to enable their NFC"
  case noReaderSession = "No reader session is available or the session isn't ready."
  case passcodeDisabled = "Passcode disabled. Please set a security passcode on your device."
  case paymentCardDeclined = "The payment card declined the transaction."
  case paymentReadFailed = "An internal failure prevented the read operation."
  case pinCancelled =  "The current PIN capture was canceled, thereby canceling any ongoing read operation."
  case pinNotAllowed = "The time window for capturing a PIN after a card read has expired."
  case pinEntryFailed = "An error occurred when capturing the PIN."
  case pinEntryTimeout = "The ongoing PIN capture was not completed within the given time."
  case pinTokenInvalid = "An error that indicates an invalid PIN token."
  case readFromBackgroundError = "Read operations aren't allowed when an app is running in the background."
  case readNotAllowed = "This error usually occurs when there's an entitlement issue."
  case readNotAllowedDuringCall = "Read operations aren't allowed during a phone call."
  case readerServiceConnectionError = "The session wasn't able to connect the system UI or other services"
  case readerServiceError = "Reader service internal state issue occurred."
  case readerSessionAuthenticationError = "An authentication error occurred while refreshing reader session"
  case readerSessionBusy = "The reader is busy with another session."
  case readerSessionExpired = "The reader session expired and couldn't refresh due to other state changes."
  case readerSessionNetworkError = "Network error occurred that prevented a reader session refresh."
  case readerTokenExpired = "The configuration token for the reader session expired."
  case vasReadFail = "Error occurred when reading a loyalty pass."    
  case invalidReaderToken = "Invalid reader token"
  case prepareFailed = "Prepare session failed"
}

Custom error messages

enum CustomErrorMessage: String {
  case entitlementIssue = "Please check the tap on phone entitlement configuration."
  case environmentIssue = "The token key environment is not acceptable."
  case deviceSupportTapOnPay = "Device Supports Tap to Pay"
  case deviceUnSupportTapOnPay = "Your current device does not support NFC."
  case readerSessionCleanUp = "Reader session cleaned up"
}

Transaction Response Details:

FieldTypeDescriptionExample
Rrn * string It’s a Unique code. Just to tracks the TXN status123456789012
DTxId * string It’s a Unique code.Its TXN hash key39676826774069372420240510183738
Label * string Its Card type VISA, AMEX
MaskedPan * string Last few digit of card number3767522012
DateNTime * string TXN date and time20240515191215
Tpn * string Device unique Identifier544424127175
TraceNo * string Its unique code to track the TXN 1
CardType * string Card type of the TXNCREDIT / DEBIT
HTxId * string It’s a Unique code. Just to tracks the TXN’s000000321000803
TxRefNo * string It’s a Unique code. Just to tracks the TXN’s034307173484
DateNTime * string It’s specify the date and time on TXN’s20240515191215
AppCode * string It’s a unique codeAXS802
RespCode * string It’s a unique code to represent a success data00
RespMsg * string It’s a response message for successAPPROVAL AXS802
BatchNo * string 63
InvoiceNo * string 5
AID * string A000000025010801
Amt string It’s a base amount 5
Label string Amount
Tax2 Amt string It’s an amount of State Tax 21
Tax2 Label string Tax2
Tax1 Amt string It’s an amount of Local Tax 11
Tax1 Label string Tax1
Tip Amt string It’s an amount of given by the Tip 20
Tip Label string Tip
Fee Amt string It’s an amount of given by the mentioned Fee9
Fee Label string Custom Fee
surveyAns string 1
Currency string It’s a currency code840

Video For Reference

iPOSgo! Deep Linking Demo Video.

support

Email us directly at devsupport@denovosystem.com with any questions or suggestions.

FAQ

  • What is a TPN?

A Terminal Profile Number (TPN) is a special code given to a payment terminal or POS device. It helps payment solution providers recognize and set up the terminal’s specific features and abilities.

  • Which iPhones and operating systems are compatible for Tap to Pay on iPhone?

Tap to Pay on iPhone requires iPhone XS or later, and the latest version of iOS. Update to the latest iOS here: https://support.apple.com/en-ca/HT204204 (opens in a new tab)

  • How do I know if the customer’s payment card is contactless?

The front or back of contactless cards have an EMV® Contactless Indicator.

  • Does Tap to Pay on iPhone work on an iPad?

Tap to Pay on iPhone is only available on an iPhone.

  • What if a customer does not have a contactless card?

In cases where the customer does not have a contactless card during the transaction, the merchant has the option to present a QR code and request the customer scan it using their smartphone and manually enter their card details.

  • What best practices can help prevent "invalid reader token" error?

A: If the JWT token has expired, it throws an error. In case TPN accepts the terms and conditions on another device, this occurs.

  • In development mode on the UAT version, what type of Apple account should I be logged into on my testing device?

A: Using a UAT version, you can use a Sandbox Account on your testing device to proceed.

  • Why does the app crash when importing our SDK?

A: As mentioned in our integration documentation, after dragging and dropping our SDK into your project, you must enable the "Embed & Sign" in Xcode’s general settings.

  • How can they resolve the integrity error that appears when trying to install the app?

A: As mentioned in our integration documentation, you can provide UDIDs for testing the devices to resolve this issue.

  • How do I start the Integration Process ?

A: Please should go through our integration documentation and contact your Dejavoo representative to guide you throughout the process.