{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-ios/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["code-walkthrough","step","admonition"]},"type":"markdown"},"seo":{"title":"Account Linking | iOS Tap to Pay on iPhone SDK Reference","description":"Link the merchant's Apple Account to Tap to Pay on iPhone with linkAccount, check link status, and understand how unlinking works.","siteUrl":"https://docs.finix.com/","llmstxt":{"hide":false,"sections":[{"title":"Getting Started","includeFiles":["guides/getting-started/**/*.md"],"excludeFiles":[]},{"title":"Online Payments","includeFiles":["guides/online-payments/**/*.md"],"excludeFiles":["guides/online-payments/payment-features/fsa-hsa-non-healthcare-mcc.md"]},{"title":"In-Person Payments","includeFiles":["guides/in-person-payments/**/*.md"],"excludeFiles":[]},{"title":"Subscriptions","includeFiles":["guides/subscriptions/**/*.md"],"excludeFiles":[]},{"title":"After the Payment","includeFiles":["guides/after-the-payment/**/*.md"],"excludeFiles":[]},{"title":"Managing Operations","includeFiles":["guides/managing-operations/**/*.md"],"excludeFiles":[]},{"title":"Platform Payments","includeFiles":["guides/platform-payments/**/*.md"],"excludeFiles":[]},{"title":"Payouts","includeFiles":["guides/payouts/**/*.md"],"excludeFiles":[]},{"title":"Low-Code / No-Code","includeFiles":["low-code-no-code/**/*.md"],"excludeFiles":[]},{"title":"Developers","includeFiles":["additional-resources/developers/**/*.md"],"excludeFiles":[]},{"title":"Plugins","includeFiles":["additional-resources/plugins/**/*.md"],"excludeFiles":[]},{"title":"Industry Considerations","includeFiles":["guides/industry-considerations/**/*.md"],"excludeFiles":[]},{"title":"Regional Considerations","includeFiles":["guides/regional-considerations/**/*.md"],"excludeFiles":[]},{"title":"Release Notes","includeFiles":["release-notes/**/*.md"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":1,"filters":{},"filesets":[{"files":[{"path":"ios/tap-to-pay/_filesets/account-linking.swift","content":[{"start":0,"condition":{"steps":["check-link-status"]},"children":["// Cached for up to linkStatusCacheDuration (default 300 seconds).","let linked = await tapToPay.isAccountLinked()","","// Bypass the cache and check with Apple directly:","let refreshed = await tapToPay.forceRefreshLinkStatus()","","// Drop the cached status so the next isAccountLinked() re-checks with Apple:","tapToPay.clearLinkStatus()"]},"",{"start":11,"condition":{"steps":["link-account"]},"children":["func enableTapToPay(using tapToPay: FinixTapToPay) async -> Bool {","    if await tapToPay.isAccountLinked() {","        return true","    }","    do {","        try await tapToPay.linkAccount() // Presents Apple's Terms and Conditions","        return true","    } catch TapToPayError.accountAlreadyLinked {","        return true // Already linked at the iOS level, so treat this as success.","    } catch TapToPayError.accountLinkingCancelled {","        return false // The merchant dismissed the sheet. Let them retry.","    } catch TapToPayError.accountLinkingRequiresiCloudSignIn {","        promptForiCloudSignIn()","        return false","    } catch {","        presentLinkError(error)","        return false","    }","}"]},"",{"start":33,"condition":{"steps":["manage-unlink"]},"children":["import UIKit","","// There is no deep link to the Tap to Pay on iPhone screen in Settings.","// Open your app's settings and direct the merchant from there:","if let settingsURL = URL(string: UIApplication.openSettingsURLString) {","    await UIApplication.shared.open(settingsURL)","}","// Then direct the merchant to: Settings > Wallet & Apple Pay > Tap to Pay on iPhone"]},""],"metadata":{"steps":["check-link-status","link-account","manage-unlink"]},"basename":"account-linking.swift","language":"swift"}],"downloadAssociatedFiles":[]}],"steps":[{"id":"check-link-status","heading":"Check link status"},{"id":"link-account","heading":"Link the account"},{"id":"manage-unlink","heading":"Manage or unlink the account"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"link-the-merchants-apple-account","__idx":0},"children":["Link the merchant's Apple Account"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before an iPhone can accept payments, the merchant must accept Apple's Tap to Pay on iPhone Terms and Conditions. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," presents Apple's sheet and links the merchant's Apple Account to Tap to Pay on iPhone."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Before you start:"]}," the SDK must be ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/installation"},"children":["initialized"]},", and the device must be signed in to iCloud."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-linking-does","__idx":1},"children":["What linking does"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Linking happens at the iOS system level. Once an Apple Account is linked for a merchant, it stays linked across app launches, and in some cases even across app reinstalls."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The Terms must be accepted by a user authorized to bind the merchant, such as an owner or administrator. If a non-admin user reaches this point, tell them to contact their administrator instead of presenting the sheet (",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/app-review"},"children":["Prepare for App Review"]}," requires this)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Linking requires an iCloud sign-in on the device; otherwise ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," throws ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".accountLinkingRequiresiCloudSignIn"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"check-link-status","__idx":2},"children":["Check link status"]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"check-link-status","heading":"Check link status"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isAccountLinked()"]}," retrieves the merchant's acceptance status from Apple. Don't track it in your own flag or database. Apple's answer is the source of truth, and App Review checks for this. The SDK caches the answer for up to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkStatusCacheDuration"]}," (default 300 seconds)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," result is reliable. A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," result can also mean the check failed or the device isn't provisioned yet, so don't treat it as proof the account is unlinked."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When you need a current answer (for example, on a settings screen), bypass the cache with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["forceRefreshLinkStatus()"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["clearLinkStatus()"]}," drops the cached status so the next ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isAccountLinked()"]}," re-checks with Apple."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"link-the-account","__idx":3},"children":["Link the account"]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"link-account","heading":"Link the account"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check the status first, then link. If the account turns out to be linked already, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," throws ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".accountAlreadyLinked"]},". Treat that as success."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"accountAlreadyLinked is success"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the merchant already accepted the Terms and Conditions, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," throws ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".accountAlreadyLinked"]},". Don't show this to the merchant as a failure. Continue on to ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/transactions#prepare-the-reader"},"children":["Prepare the reader"]},"."]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"manage-or-unlink-the-account","__idx":4},"children":["Manage or unlink the account"]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"manage-unlink","heading":"Manage or unlink the account"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["There is no API to unlink an Apple Account from Tap to Pay on iPhone, because the link lives at the iOS system level. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["clearLinkStatus()"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["clearAllCaches()"]}," only reset the SDK's local caches. They never unlink the account."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Deleting and reinstalling the app usually returns it to an unlinked state, but because the link is system-level it can survive a reinstall (see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"#what-linking-does"},"children":["What linking does"]},"). After reinstalling, check with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["forceRefreshLinkStatus()"]},": ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," means the link survived. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," doesn't guarantee the link is gone, since the check also returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," when it fails or the device isn't provisioned yet. If you need a guaranteed unlinked state (for testing or ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/app-review"},"children":["App Review recordings"]},"), use a device and Apple Account pair that has never been linked for the merchant."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Merchants can review the linked account in the Settings app under ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Wallet & Apple Pay ▸ Tap to Pay on iPhone"]},". iOS doesn't provide a deep link to that screen. The best your app can do is open its own settings and direct the merchant from there."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Next:"]}," ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/transactions#prepare-the-reader"},"children":["Prepare the reader"]},"."]}]}]},"headings":[{"value":"Link the merchant's Apple Account","id":"link-the-merchants-apple-account","depth":1},{"value":"What linking does","id":"what-linking-does","depth":2},{"value":"Check link status","id":"check-link-status","depth":2},{"value":"Link the account","id":"link-the-account","depth":2},{"value":"Manage or unlink the account","id":"manage-or-unlink-the-account","depth":2}],"frontmatter":{"seo":{"title":"Account Linking | iOS Tap to Pay on iPhone SDK Reference","description":"Link the merchant's Apple Account to Tap to Pay on iPhone with linkAccount, check link status, and understand how unlinking works."},"markdown":{"toc":{"hide":true}},"footer":{"hide":true}},"lastModified":"2026-08-11T19:49:07.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/ios/tap-to-pay/account-linking","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}