This Package is an SDK that facilitates enabling Apple's Tap To Pay on iPhone functionality in your own app. With just a bit of configuration and a few lines of code, your iPhone app will be able to securely accept contactless payments on a supported iPhone without any additional hardware (e.g. POS terminal, external card reader device, etc.)
Currently this functionality is only available in the U.S.
By using this Package, you will not need to certify your app. We have taken care of that for you.
Apple Tap to Pay on iPhone requires iPhone XS or later.
Transaction Type | Minimum iOS Version |
---|---|
Credit | iOS 16.7 |
Debit | iOS 16.7 |
You must request a special entitlement from Apple to enable Tap To Pay. Log-into your Apple Developer Account and then click here to request the entitlement. In the text box titled 'PSP, enter 'Fiserv' as the value.
Follow the instructions here to add the entitlement to your app's profile
You can obtain test credentials for your app on Fiserv's Developer Studio by following these directions:
CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your Podfile
:
pod 'FiservTTP'
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler.
Create a new project or open your existing app in XCode.
Add the Fiserv Package to your app by following these instructions:
https://github.com/Fiserv/TTPPackage
Create an instance of FiservTTPConfig
and load it with your configuration as follows:
let myConfig = FiservTTPConfig(
secretKey: "<your secret key from Developer Studio>",
apiKey: "<your API key from Developer Studio>",
environment: .Sandbox,
currencyCode: "USD",
appleTtpMerchantId: "<optional apple ttp merchantId provided by fiserv>",
merchantId: "<your merchantId from the CommerceHub workspace on Developer Studio>",
merchantName: "<your merchant name as it will be displayed in the Tap to Pay payment sheet>",
merchantCategoryCode: "<your MCC>",
terminalId: "10000001", /// Identifies the specific device or point of entry where the transaction originated assigned by the acquirer or the gateway
terminalProfileId: "3c00e000-a00e-2043-6d63-936859000002") /// Unique identifier for the terminal profile used to configure the kernels of the card reader and manage payment terminal behavior
Now create an instance of FiservTTPCardReader
, which is the main class that your app will interact with. Typically you would put this in a view model.
private let fiservTTPCardReader: FiservTTPCardReader = FiservTTPCardReader(configuration: myConfig)
Early in the startup process of your app, call the following method to validate that the device running your app is supported for Apple Tap To Pay on iPhone:
if !fiservTTPCardReader.readerIsSupported() {
// TODO handle unsupported device
}
You must obtain a session token in order to utilize the SDK. Acquire the token by making this call:
do {
try await fiservTTPCardReader.requestSessionToken()
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
Note that the session token has a time to live of 48 hours. However, we have included an auto-refresh feature that will request a new token for you when the TTL value is 30 minutes or less. Moving the app from the background to the foreground, as well as unlocking (a locked iPhone) will trigger this check and the refresh will occur based on the time remaining of the token.
Additional information can be found here: Commerce Hub Security
Next you must link the device running the app to an Apple ID. This needs to happen just once. You are responsible for tracking whether the linking process has occurred already or not. If not, then perform linking by making this call:
do {
try await fiservTTPCardReader.linkAcount()
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
When targeting iOS 16.4 or greater, the option to check if the account is already linked is available.
do {
let isLinked = try await fiservTTPCardReader.isAccountLinked()
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
Additional information can be found here: isAccountLinked
Now you're ready to initialize the Apple Proximity Reader by calling:
do {
try await fiservTTPCardReader.initializeSession()
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
NOTE: that you must re-initialize the reader session each time the app starts.
Congrats on getting this far! Now you are ready to process your first payment. Simply make this call and the SDK takes care of the rest for you:
let amount = 10.99 // amount to charge
let merchantOrderId = "your order ID, for tracking purposes"
let merchantTransactionId = "your transaction ID, for tracking purposes"
do {
let chargeResponse = try await fiservTTPCardReader.readCard(amount: amount,
merchantOrderId: merchantOrderId,
merchantTransactionId: merchantTransactionId)
// TODO inspect the chargeResponse to see the authorization result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
NOTE: If the card used for the charges endpoint is PIN DEBIT, the user will see a pin entry screen after tapping the card.
Additional information can be found here: Commerce Hub Charges
let amount = 10.99 // amount to void
let referenceTransactionId = "this value was returned in the charge response"
do {
let voidResponse = try await fiservTTPCardReader.voidTransaction(amount: amount,
referenceTransactionId = referenceTransactionId)
// TODO inspect the voidResponse to see the result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
Additional information can be found here: Commerce Hub Cancel
At least one reference transaction identifier must be provided to perform a Tagged Refund.
let amount = 10.99 // amount to void
let referenceTransactionId = "this value was returned in the charge response"
do {
let refundResponse = try await fiservTTPCardReader.refundTransaction(amount: amount,
referenceTransactionId = referenceTransactionId)
// TODO inspect the refundResponse to see the result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
NOTE: If using PIN DEBIT, refer to the Unmatched-Tagged Refund below.
Additional information can be found here: Commerce Hub Matched Refund
NOTE: The fiservTTPCardReader.refundCard API supports both 'Unmatched Tagged Refunds' and 'Open Refunds'.
Open Refund
An open refund (credit) is a refund to a card without a reference to the prior transaction.
To perform an Open Refund, do not provide any reference transaction identifiers, but your merchantOrderId or merchantTransactionId can be passed as an argument.
let amount = 10.99 // amount to void
let referenceTransactionId = "this value was returned in the charge response"
do {
let refundResponse = try await fiservTTPCardReader.refundCard(amount: amount),
merchantTransactionId: transactionId)
// TODO inspect the refundResponse to see the result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
Additional information can be found here: Commerce Hub Open Refund
Unmatched Tagged Refund
To perform an Unmatched Tagged Refund, the referenceTransactionId or the referenceMerchantTrancation must be provided. It is also acceptable to provide all values as well.
An unmatched tagged refund allows a merchant to issue a refund to a payment source other than the one used in the original transaction. The refund is associated with the original charge request by using the Commerce Hub transaction identifier or merchant transaction identifier. This allows the merchant to maintain the linking of the transaction information in Commerce Hub when issuing a refund or store credit.
Unmatched Tagged Refund example:
let amount = 10.99 // amount to void
let referenceTransactionId = "this value was returned in the charge response"
do {
let refundResponse = try await fiservTTPCardReader.refundCard(amount: amount),
referenceTransactionId: referenceTransactionId,
referenceMerchantTransactionId: referenceMerchantTransactionId)
// TODO inspect the refundResponse to see the result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
NOTE: If the card used for the refund card endpoint is PIN DEBIT, the user will see a pin entry screen after tapping the card.
Additional information can be found here: Commerce Hub Unmatched Refund
To retrieve the current state of any previous transaction, an inquiry request can be submitted against the Commerce Hub transaction identifier or merchant transaction identifier.
NOTE: At least one of the arguments must be provided.
do {
let inquireResponse = try await fiservTTPCardReader.inquiryTransaction(referenceTransactionId: referenceTransactionId,
referenceMerchantTransactionId: referenceMerchantTransactionId,
referenceMerchantOrderId: referenceMerchantOrderId,
referenceOrderId: referenceOrderId)
// TODO inspect the Inquire Response to see the result
} catch let error as FiservTTPCardReaderError {
// TODO handle exception
}
Additional information can be found here: Commerce Hub Inquiry
We've prepared an end-to-end sample app to get you up and running fast. Get the Sample App here
Merchant FAQ's from Apple Tap to Pay on iPhone Security from Apple