Accept Tap to Pay payments
This guide walks through integrating Tap to Pay using Payabli’s mobile SDK. To learn how Tap to Pay works, see the Tap to Pay overview.
Prerequisites
Before you start, confirm you have:
- A physical device. An iPhone XS or newer running iOS 16.7 or later.
- Payabli sandbox credentials. A Payabli sandbox
entryPointwith Tap to Pay enabled. Contact your Payabli representative if you don’t have one yet. - Your app registered on the paypoint allowlist. Your app’s
appId(<TEAM_ID>.<BUNDLE_ID>) must be authorized on the entrypoint before device attestation succeeds. See Integration steps. - Apple’s Tap to Pay entitlement.
com.apple.developer.proximity-reader.payment.acceptance. Request it through the Apple Developer Portal. - Xcode 15 or later and Swift 5.9 or later.
Apple’s Tap to Pay entitlement (com.apple.developer.proximity-reader.payment.acceptance) needs Apple’s approval before you can use it. Request it through the Apple Developer Portal. Approval can take 2–8 weeks. Apply for this entitlement as soon as you decide to integrate Tap to Pay. Don’t wait until the rest of your integration is ready.
Your app’s provisioning profile also needs com.apple.developer.devicecheck.appattest-environment, set to development for development builds or production for release builds. This value must match the environment you pass to PayabliTTP.
Integration steps
Register your app, set up a backend token proxy, then work through the SDK from installation to your first charge:
Register your app on the paypoint allowlist
Before your app can complete device attestation, authorize its appId (<TEAM_ID>.<BUNDLE_ID>) on the entrypoint’s allowlist. Do this once per app, from your backend or a provisioning script.
deviceOs must be "ios". friendlyName is optional. This endpoint is idempotent on (entryPoint, deviceOs, appId), so it’s safe to call from an automated provisioning script. If appId isn’t registered, the SDK’s initialize() method rejects attestation with PayabliTTPError.attestationFailed.
Build the backend token proxy
Tap to Pay uses the same access token model as the rest of the mobile SDK: your backend holds the Payabli clientSecret, exchanges it for a short-lived access token, and never exposes it to the app. See Backend token endpoint in the Tap to Pay component reference for more information.
Install the SDK
Add PayabliSDKTapToPay from the sdk-ios Swift package and link the PayabliSDKTapToPay product. See Installation in the Tap to Pay component reference for more information.
Initialize and handle first-time activation
The interactive walkthrough displays code examples alongside step-by-step explanations.
On a device’s first launch, initialize() throws PayabliTTPError.devicePendingActivation. See How first-time activation works for the full sequence. Handle it by prompting for a code and calling activateDevice(activationCode:).
/// Add the import and token provider
Import PayabliSDKTapToPay and add a function that exchanges credentials with your backend for a Payabli access token. See Integration steps for the backend side of this exchange.
/// Create the PayabliTTP instance
Construct PayabliTTP with your entryPoint, the app’s appId (<TEAM_ID>.<BUNDLE_ID>), and your token provider. The environment you pass here must match the appattest-environment entitlement in your provisioning profile.
/// Handle first-time activation
Call initialize() on launch. On a device’s first run, it throws PayabliTTPError.devicePendingActivation instead of completing. Your backend requests a one-time activation code from Payabli and delivers it to the user. The SDK doesn’t generate the code itself. Prompt the user for the code, call activateDevice(activationCode:), then retry initialize().
Process a payment
Once start() completes without throwing, ttp is in the .ready state and can accept a charge:
charge(type:paymentDetails:customer:invoice:orderDescription:) does three things in order: it calls POST /MoneyIn/initiate (which creates the transaction’s paymentTransId), prompts the NFC card read, then calls PATCH /MoneyIn/update/{paymentTransId}. See Implementation reference for the full parameter list.
On success, charge(...) returns a TransactionResult with a single field, paymentTransId. Store it alongside your order record — it’s the identifier you use to find or reconcile the transaction later.
Capturing paymentTransId for reconciliation
If the final /update call fails after retries, the transaction may still be authorized by the processor even though charge(...) throws, and the thrown PayabliTTPError.updateFailed(reason:) doesn’t carry the transaction ID. Subscribe to ttp.events() and store paymentTransId from .chargeInitiated, which fires as soon as /initiate succeeds, before any card is read:
Testing
Tap to Pay requires a physical device to test. There are two ways to test Tap to Pay in your app:
- NFC test cards. The recommended option during development and testing. A physical card is easier to use than a second device, because you don’t have to unlock a phone and tap it for every test payment. Check with your Payabli representative for supported test card vendors and ordering details.
- A second device with a test wallet card. Create an Apple Pay sandbox tester account, sign in to a second iPhone with it, then add test cards to Wallet on that device. Tap the provisioned card against the device running your app. This option is free and works well for routine development. You should still use test cards before you finish your integration.
Next steps
Tap to Pay documents the full PayabliTTP implementation reference, plus a complete example app you can clone and run.
Related resources
See these related resources to help you get the most out of Payabli.
Prerequisites
- Tap to Pay overview - Learn how Tap to Pay lets your app accept contactless, card-present payments with no external hardware