Skip to content

Device

Every iPhone that accepts payments is represented in Finix by a Device. The SDK requires the Device's ID at initialization.

Each Tap to Pay on iPhone Device represents one Merchant on one physical iPhone. Finix identifies the iPhone by Apple's reader identifier, which you pass as the Device's serial_number during creation.

Get the reader identifier

Apple assigns each iPhone a stable reader identifier that becomes the Device's serial_number.

Check for an existing Device

List existing Devices for a Merchant and match on serial_number. A Device whose serial_number matches the reader identifier and whose enabled is true can be reused; no new provisioning needed.

Create the Device

POST /merchants/{merchant_id}/devices

FieldValue
modelAlways IOS_TAP_TO_PAY.
serial_numberThe Apple reader identifier.
app_bundle_idYour app's bundle identifier. Must match the app that takes payments.
name, descriptionFree-form labels shown in the Finix Dashboard.

The response returns the new Device with "enabled": false. The Device must be activated before it can process transfers.

Response
{
  "id": "DVxxxxxxxxxxxxx",
  "enabled": false,
  "model": "IOS_TAP_TO_PAY",
  "merchant": "MUxxxxxxxxxxxxx",
  "name": "Tap to Pay on iPhone - Front Counter",
  "serial_number": "{reader_identifier}",
  "created_at": "2026-08-04T17:32:11.000Z"
}

Activate the Device

PUT /devices/{device_id}

FieldValue
actionACTIVATE

The response returns the Device with "enabled": true. Transactions on an un-activated Device fail at processing time, not at initialization.

Cache and reuse the Device ID

A Device ID is stable per (Merchant, reader identifier) pair. Cache the ID keyed by both; invalidate the cache when a transaction fails with a Device-not-activated or Device-not-enabled error.

import ProximityReader

func fetchReaderIdentifier() async throws -> String {
    try await PaymentCardReader().readerIdentifier
}

func tapToPayDeviceId(merchantId: String, readerIdentifier: String) async throws -> String {
    let cacheKey = "finix_ttp_device_\(merchantId)_\(readerIdentifier)"
    if let cached = UserDefaults.standard.string(forKey: cacheKey) {
        return cached
    }
    // Your backend looks up or creates + activates the Device for
    // (merchantId, readerIdentifier) and returns its ID.
    let deviceId = try await backend.provisionTapToPayDevice(
        merchantId: merchantId,
        readerIdentifier: readerIdentifier
    )
    UserDefaults.standard.set(deviceId, forKey: cacheKey)
    return deviceId
}