Skip to content

PAX D135 iOS Quickstart

Use the Finix iOS SDK to integrate the PAX D135 Bluetooth card reader into your iOS app and accept in-person payments. This guide covers SDK installation, initialization, and processing your first transaction.

Prerequisites

Before starting, complete the Integration Prerequisites to configure your environment, credentials, and a Device resource.

1. SDK setup and connection

Installation

Add the SDK to your project via Swift Package Manager using:

https://github.com/finix-payments/finix-pax-mpos-ios-sdk

Initialization

Pre-requisites

  • iOS 15.6 or later
  • iOS device. Simulator not supported
  • Add Bluetooth permission in Info.plist using key Privacy - Bluetooth Always Usage Description

To interact with the MPOS device, first initialize the SDK

import PaxMposSDK

let finixClient = FinixClient(config: FinixConfig(
            environment: TEST_ENVIRONMENT,
            credentials: Finix.APICredentials(username: TEST_USERNAME, password: TEST_PASSWORD),
            application: TEST_APPLICATION,
            version: TEST_VERSION,
            merchantId: TEST_MERCHANT_ID,
            mid: TEST_MERCHANT_MID,
            deviceType: .Pax,
            deviceId: "") //Device ID - device registers with Finix, starting with DV (i.e. DVxxxx)
)
finixClient.delegate = self
finixClient.interactionDelegate = self

Once initialized, connect to the Device. When the Device is ready for pairing, it will show an orange light and green light. Once connected, the orange light will disappear and only the green light will stay on.

First Time Device Configuration

When first pairing a PAX D135 the initial configuration may take a few minutes to complete. We recommended that the user experience you build factors in the configuration time to ensure that the user knows the device configuration is in progress.

Scanning for devices

Call startScan() to scan for nearby D135 devices over Bluetooth. The didDiscoverDevice callback fires for each Device found.

finixClient.startScan()

extension ViewController: FinixDelegate {
    func didDiscoverDevice(_ deviceInfo: DeviceInfo) {
        devices.append(deviceInfo)
    }
}

Connecting to the device

Pass the selected device's Bluetooth ID (device.id) to connectDevice(). The deviceDidConnect callback fires when the connection is established.

finixClient.connectDevice(device.id)

extension ViewController: FinixDelegate {
    func deviceDidConnect(_ deviceInfo: DeviceInfo) {
        connectedDevice = deviceInfo
    }
}

2. Creating a Device

Create a Device under the Merchant provisioned to process in-person payments. Include the model of the payment terminal you'll be using to process cards.

curl -i -X POST \
  -u USfdccsr1Z5iVbXDyYt7hjZZ:313636f3-fac2-45a7-bff7-a334b93e7bda \
  https://finix.sandbox-payments-api.com/merchants/MUwfZPNW3r4EqLMzwgr6txw4/devices \
  -H 'Content-Type: application/json' \
  -H 'Finix-Version: 2022-02-01' \
  -d '{
    "configuration": {
      "allow_debit": true,
      "allow_standalone_authorizations": false,
      "allow_standalone_refunds": false,
      "allow_standalone_sales": false,
      "bypass_device_on_capture": true,
      "check_for_duplicate_transactions": true,
      "display_tip_on_receipt": false,
      "prompt_amount_confirmation": true,
      "prompt_manual_entry": false,
      "prompt_receipt_confirmation": true,
      "prompt_tip_on_screen": false,
      "tipping_details": {
        "allow_custom_tip": true,
        "fixed_options": [
          100,
          150,
          200
        ],
        "percent_options": [
          18,
          20,
          22
        ],
        "percent_tipping_threshold": 0
      }
    },
    "description": "Cashier Three",
    "integration_mode": "PAYMENT_APP",
    "model": "PAX_D135",
    "name": "My PAX_D135 Finix Device",
    "serial_number": "1904626094"
  }'

A successful response returns the Device resource you'll use to initialize the SDK.

Model PAX_D135 Device
{
  "id": "DVxcL2fiBdt9frYCKAbZikZK",
  "created_at": "2025-05-21T19:01:32.000581Z",
  "updated_at": "2025-05-21T19:01:32.000581Z",
  "configuration_details": {
    "allow_debit": true,
    "check_for_duplicate_transactions": true,
    "prompt_amount_confirmation": true,
    "prompt_manual_entry": false,
    "signature_threshold_amount": 10000,
    "bypass_device_on_capture": true,
    "prompt_receipt_confirmation": true,
    "display_tip_on_receipt": false,
    "prompt_tip_on_screen": false,
    "allow_standalone_authorizations": false,
    "allow_standalone_sales": false,
    "allow_standalone_refunds": false,
    "tipping_details": {
      "percent_tipping_threshold": 0,
      "percent_options": [
        18,
        20,
        22
      ],
      "fixed_options": [
        100,
        150,
        200
      ]
    },
    "idle_message": null,
    "idle_image_file_id": null,
    "automatic_receipt_delivery_methods": null,
    "available_receipt_methods": null,
    "prompt_for_signature": "NEVER",
    "surcharge_basis_points": null
  },
  "description": "Cashier Three",
  "enabled": false,
  "idle_message": null,
  "integration_mode": "PAYMENT_APP",
  "merchant": "MU7noQ1wdgdAeAfymw2rfBMq",
  "model": "PAX_D135",
  "name": "My PAX_D135 Finix Device",
  "serial_number": "19046260947",
  "tags": {},
  "_links": {
    "self": {
      "href": "https://finix.sandbox-payments-api.com/devices/DVxcL2fiBdt9frYCKAbZikZK"
    },
    "merchant": {
      "href": "https://finix.sandbox-payments-api.com/merchants/MU7noQ1wdgdAeAfymw2rfBMq"
    },
    "transfers": {
      "href": "https://finix.sandbox-payments-api.com/transfers"
    },
    "authorizations": {
      "href": "https://finix.sandbox-payments-api.com/authorizations"
    }
  }
}

3. Starting a transaction

Update the client with the Finix Device ID, then call startTransaction(). The device shows a blue light and prompts the customer to tap, swipe, or insert their card. Once the card is read, the light turns red, indicating the customer should remove their card.

finixClient.update(deviceId: "DVxxxxx")
let transactionAmount = Currency(amount: Int(amountDouble * 100), code: .USD)
finixClient.startTransaction(
    amount: transactionAmount,
    type: transactionType,
    splitTransfers: nil,
    tags: nil,
    buyerIdentityId: nil
) { transferResponse, error in
    Task { @MainActor in
        // Handle using transferResponse and error
    }
}

Referenced refund

A referenced refund refunds the amount specified (refund amount) of a particular transaction (transaction ID) to the card on file.

/// Start a referenced refund
    func startRefund(transactionID: String, amount: Currency, completion: ((RefundResponse?, Error?) -> Void)?) {
        let mainCompletion: (RefundResponse?, Error?) -> Void = { response, error in
            if let error {
                self.logger.error("startRefund failed with error: \(error)")
            }

            DispatchQueue.main.async {
                completion?(response, error)
            }
        }

        let externalEndpoint = FinixAPIEndpoint.externalEndpoint(config.environment)
        let endPoint = "transfers/\(transactionID)/reversals"
        guard let url = URL(string: endPoint, relativeTo: externalEndpoint) else {
            mainCompletion(nil, FinixError(code: .MalformedRequest, message: "Could not encode path!"))
            return
        }

        guard let request = requestBuilder(url: url, method: .POST, payload: ["refund_amount": amount.amount]) else {
            mainCompletion(nil, FinixError(code: .CannotEncodeParameters, message: "Cannot encode request parameters"))
            return
        }

        finixRequest(request: request) { (response: RefundResponse?, error: Error?) in
            print(response as Any, error as Any)
            mainCompletion(response, error)
        }
    }

Troubleshooting

If you encounter issues, use sendDebugReport to collect diagnostic information from the Device and send the logs to Finix Support to help troubleshoot the issue.

Send Debug Data - iOS
func sendDebugData() {}
Note

Alternatively, you can send debug logs using the Sample App.