# Tap to Pay on iPhone

To process transactions with Tap to Pay on iPhone, integrate Moov's iOS SDK, [MoovKit](https://moovfinancial.github.io/moov-ios/documentation/moovkit/getting-started/).

Accept all types of in-person, contactless payments right on your iPhone with no extra terminals or hardware needed. Accept physical debit and credit cards, Apple Pay, and other digital wallets. Tap to Pay on iPhone uses the built-in security and privacy features of iPhone to help protect your business and customer data.

![We're sorry, the video element could not load.](images/ttpoi-poster.webp)

This guide outlines how to set up Tap to Pay on iPhone. For the best results, merchants should implement code that prevents the screen or application from sleeping. If the screen or application sleeps while a transaction is in-flight, processing may be interrupted or fail. Additionally, ensure **developer mode** on the device is turned off before starting any transaction in production mode.

To use Tap to Pay on iPhone, you'll need to integrate with Moov's SDKs. Integration consists of two main phases:

1. **Onboard Terminal Applications** – Register terminal applications then link them with a merchant
2. **Accept and Process Payments** – Configure the merchant’s mobile application to process contactless payments

View Moov's full [iOS SDK (MoovKit)](https://moovfinancial.github.io/moov-ios/documentation/moovkit/getting-started/) documentation for more information.

## [Prerequisites &amp; supported devices](#prerequisites--supported-devices)

Ensure the app is running on a compatible device and iOS version. You can use [isPaymentCardSupported()](https://moovfinancial.github.io/moov-ios/documentation/moovkit/moov/ispaymentcardsupported%28%29) to verify device compatibility.

- iPhone XS or newer
- iOS 16.0+ (US)
- Latest iOS version recommended for optimal performance

## [Integrate MoovKit](#integrate-moovkit)

Moov's SDK to integrate Tap to Pay on iPhone functionality is available for [download](https://github.com/moovfinancial/moov-ios) and you can find more details in the [documentation](https://moovfinancial.github.io/moov-ios/documentation/moovkit/).

Add MoovKit as a package dependency to your project via via Swift Package Manager.

```fallback
https://github.com/moovfinancial/moov-ios
```

Within the project you'll also need to embed the framework and link binary with libraries. See the [MoovKit](https://moovfinancial.github.io/moov-ios/documentation/moovkit/getting-started) documentation for complete details.

And finally, add MoovKit to your project.

```swift
import MoovKit
```

## [Request entitlement from Apple](#request-entitlement-from-apple)

Your application must request an entitlement from Apple for Tap to Pay on iPhone. You can request from your [Apple Developer Account](https://developer.apple.com/contact/request/contactless-payments).

After receiving the entitlement, you should configure the entitlement in your project. View the full instructions on [developer.apple.com](https://developer.apple.com/documentation/proximityreader/setting-up-the-entitlement-for-tap-to-pay-on-iphone).

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.proximity-reader.payment.acceptance</key>
    <true/>
</dict>
</plist>
```

## [Review Apple's guidelines](#review-apples-guidelines)

Before submitting your application, review Apple’s [human interface guidelines](https://developer.apple.com/design/human-interface-guidelines/tap-to-pay-on-iphone) to ensure your implementation follows all requirements to avoid any delays in the approval process.

## [Implement terminal configuration provider](#implement-terminal-configuration-provider)

Implement a terminal configuration provider to initialize MoovKit. For production use, fetch the configuration from your backend. Below is a sample implementation, assuming `PartnerClient` is implemented to interact with your backend API:

```swift
import Foundation
import PartnerClient
import os

class TerminalConfigProvider: TerminalConfigurationProvider {
  let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "main")
  
  var terminalConfiguration: String {
    get async throws {
        return try await fetch(terminalApplicationID: UUID(uuidString: "7922ce07-daf3-48f2-aab3-ed878c76a1a3")!)
    }
  }

  let partnerClient: PartnerClient
  let partnerAccountID: UUID
  let merchantAccountID: UUID

  public init(partnerClient: PartnerClient, partnerAccountID: UUID, merchantAccountID: UUID) {
    self.partnerClient = partnerClient
    self.partnerAccountID = partnerAccountID
    self.merchantAccountID = merchantAccountID
  }

  func fetch(terminalApplicationID: UUID) async throws -> String {
    do {            
      let terminalConfig = try await partnerClient.getTerminalConfiguration(
        accountID: merchantAccountID,
        terminalApplicationID: terminalApplicationID
      )
      return terminalConfig.configuration
    } catch {
      logger.error("\(error)")
      throw error
    }
  }
}
```

View the [SDK](https://moovfinancial.github.io/moov-ios/documentation/moovkit/getting-started/#6-Configure-Terminal-Provider) documentation for more details and context.

## [Register application](#register-application)

Applications must be registered with Moov to be authorized to use [MoovKit](https://moovfinancial.github.io/moov-ios/documentation/moovkit/getting-started/). The process for application registration is as follows:

1. Create a TerminalApplication via the create terminal application [endpoint](/api/sources/terminal-applications/create/)

```zsh
curl -X POST "/terminal-applications" \
  -H "Authorization: Bearer {token}" \
  --data '{
    "platform": "android"
  }'\
```

2. The application will move from `pending` to `enabled` once approved. You can subscribe to the `terminalAppRegistration.updated` webhook to be notified of the status updates
3. Once the application is enabled, you must link the app's `TerminalApplication` to a merchant account via the link terminal application [endpoint](/api/sources/terminal-applications/link/)

```zsh
curl -X POST "/accounts/{accountID}/terminal-applications" \
  -H "Authorization: Bearer {token}" \
  --data '{
    "terminalApplicationID": "string"
  }'\
```

## [Terms &amp; condition acceptance](#terms--condition-acceptance)

Merchants need to accept Apple's terms and conditions - once for each merchant identifier. Once the terms and conditions are accepted, any device using the same merchant identifier can use Tap to Pay on iPhone without accepting the terms and conditions again. The additional devices don’t need to use the same Apple account, or be signed in to Apple.

For the best user experience, it’s recommended to present the terms and conditions before the checkout experience.

View [Apple's documentation](https://developer.apple.com/documentation/ProximityReader/adding-support-for-tap-to-pay-on-iphone-to-your-app#Display-the-Terms-and-Conditions-interface-to-the-merchant) for more information on terms and conditions.

## [Create transfer](#create-transfer)

Tap to Pay on iPhone uses the built-in security and privacy features of iPhone to help protect your business and customer data. When a payment is processed, Apple doesn’t store card numbers on iPhone or on Apple servers.

1. Once terms and conditions have been accepted, initialize the reader hardware.

```swift
do {
  let identifier = try await moov.initReader()
  logger.debug("identifier \\(String(describing: identifier))")
} catch {
  logger.error("Failed to fetch identifier")
}
```

2. Create a payment session by calling `createSession(invalidateTerminalConfiguration:)` as early as possible to configure the device.

💡 Each time your app launches, create a `PaymentCardReaderSession` to handle the reading of payment card information. You create this session using the `createSession(invalidateTerminalConfiguration:)` method of your Moov object. The initial configuration of the device can take up to two minutes, but subsequent requests typically take only a few seconds. Register an `eventHandler:` to receive an asynchronous stream of events that you can use to display a progress UI to the merchant.

There are two main paths to accept EMV payments:

- Directly create a `transfer` from the SDK
- Create an authorization via the SDK and create the `transfer` separately

[Directly create transfer](#tab-589234176-2-0) [SDK authorization &amp; transfer API](#tab-589234176-2-1)

This method accepts the EMV tap, authorizes the transaction with the card network, creates a transfer on the Moov platform, and returns the transfer ID.

```swift
do {
  let accessToken = // source from Moov backend
  let paymentMethodId = // source from Moov backend
  let transfer = try await moov.createTapTransfer(
    for: amount, 
    currencyCode: CurrencyCode.USD, 
    transactionType: .purchase, 
    destinationPaymentMethodId: paymentMethodId, 
    customerAccountId: nil, 
    description: nil, 
    using: accessToken
	)
} catch {
	logger.error("Card read error: \(error)")
}
```

This method accepts the EMV tap, authorizes the transaction with the card network, and returns a token which can be passed into the [create transfer](/api/money-movement/transfers/create/) API.

```swift
do {
  let amt = Decimal(1.23)
  let authResponse = try await moov.createTapAuthorization(
    for: amount,
    currencyCode: CurrencyCode.USD,
    transactionType: .purchase,
    customerAccountID: UUID()
  )
    
// send authResponse.paymentToken to your backend to create a transfer using authorization as the source
} catch {
  logger.error("Card read error: \(error)")
}
```

## [Test mode](#test-mode)

[Test mode](/guides/get-started/test-mode/) allows you to explore and verify your integration with the MoovKit SDK before processing live payments. The terminal configuration fetched from the Moov API determines whether the SDK operates in test or production mode. In test mode, MoovKit provides access to features and methods specifically designed for testing and simulating various scenarios.

Select from predefined test cards to simulate different authorization outcomes, including approvals and declines, without requiring a physical card tap. Instead of requiring a physical card tap the SDK will present a screen to select a card to use. See the [Tap to Pay](/guides/developer-tools/test-data/#tap-to-pay-on-mobile) section of the test mode data reference for available test cards.

Test mode is also supported on the iPhone Simulator, allowing you to develop and test your integration without a physical device.

Refer to the [iOS SDK](https://moovfinancial.github.io/moov-ios/documentation/moovkit/test-mode) documentation for complete details on how to use test-specific functionality.

## [Error handling](#error-handling)

MoovKit communicates errors with your application via exceptions. View the documentation for the following error types:

- [SDKError](https://moovfinancial.github.io/moov-ios/documentation/moovkit/sdkerror)
- [CardReaderError](https://moovfinancial.github.io/moov-ios/documentation/moovkit/cardreadererror)
- [CardReadError](https://moovfinancial.github.io/moov-ios/documentation/moovkit/cardreaderror)

If you encounter any issues, please create a [support ticket](https://portal.usepylon.com/moov/forms/problem) and attach the SDK logs. Be sure to include:

- The SDK version and OS/device details
- A description of the steps that led to the error
- The relevant portion of the logs (compressed if large)
- Ensure any sensitive information (API keys, card details, or PII) is redacted

* * *

Tap to Pay on iPhone requires a supported payment app and the latest version of iOS. Update to the latest version by going to Settings &gt; General &gt; Software Update. Tap Download and Install. Some contactless cards may not be accepted by your payment app. Transaction limits may apply. The Contactless Symbol is a trademark owned by and used with permission of EMVCo, LLC. Tap to Pay on iPhone is not available in all markets. For Tap to Pay on iPhone countries and regions, see [https://developer.apple.com/tap-to-pay/regions/](https://developer.apple.com/tap-to-pay/regions/).
