Skip to content

Repository files navigation

MONEI Pay iOS SDK

Accept NFC tap-to-pay payments in your iOS app via MONEI Pay.

No special entitlements, certificates, or Apple approval needed — your app opens MONEI Pay, which handles the NFC payment, then calls back with the result.

Requirements

  • iOS 15.0+
  • MONEI Pay installed on device
  • POS auth token from your backend (POST /v1/pos/auth-token)

Installation

Use the latest release. Git tags look like v1.2.3; SwiftPM and CocoaPods expect semver without the v. CocoaPods also lists the pod here.

Swift Package Manager

In Xcode: File → Add Package Dependencieshttps://github.com/MONEI/monei-pay-ios-sdk.git → pick a rule tied to the version on the latest release (e.g. Up to Next Major from that version).

In Package.swift, set from: to the semver from the latest release page:

dependencies: [
    .package(url: "https://github.com/MONEI/monei-pay-ios-sdk.git", from: "X.Y.Z")
]

CocoaPods

In your Podfile:

pod 'MoneiPaySDK'

Then run pod install (resolves the current release on trunk).

Setup

1. Register your callback URL scheme

In your app's Info.plist, register a custom URL scheme (e.g. your bundle ID):

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>my-merchant-app</string>
        </array>
    </dict>
</array>

2. Add MONEI Pay to queried schemes

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>monei-pay</string>
</array>

The SDK launches MONEI Pay via a Universal Link (https://pay.monei.com/accept-payment), which opens the app directly with no "Open in MONEI Pay?" prompt. On MONEI Pay installs that predate Universal Link support it transparently falls back to the monei-pay:// custom scheme (hence the queried scheme above is still required). No merchant configuration is needed beyond the steps here.

3. Wire the complete-redirect handler

SwiftUI:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    MoneiPay.handleCompleteRedirect(url: url)
                }
        }
    }
}

UIKit:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    return MoneiPay.handleCompleteRedirect(url: url)
}

Usage

Two complementary result channels:

  • completeScheme — your app's URL scheme. MONEI Pay opens <completeScheme>://payment-result?... on completion. UX-only, untrusted; use for navigation/UI.
  • callbackUrl (optional) — HTTPS endpoint on your backend. MONEI fires a signed webhook (MONEI-Signature HMAC). Use for fulfillment, accounting, anything irreversible.
import MoneiPaySDK

do {
    let result = try await MoneiPay.acceptPayment(
        token: "eyJ...",              // Raw JWT from your backend (no "Bearer " prefix)
        amount: 1500,                 // Amount in cents (1500 = 15.00 EUR)
        description: "Order #123",    // Optional
        customerName: "John Doe",     // Optional
        customerEmail: "john@ex.com", // Optional
        customerPhone: "+34600000000",// Optional
        callbackUrl: "https://merchant.example.com/webhook/monei", // Optional, signed webhook
        completeScheme: "my-merchant-app"  // Your registered URL scheme
    )

    print("Payment approved: \(result.transactionId)")
    print("Card: \(result.cardBrand ?? "") \(result.maskedCardNumber ?? "")")
} catch MoneiPayError.moneiPayNotInstalled {
    // Prompt user to install MONEI Pay
} catch MoneiPayError.paymentCancelled {
    // User cancelled
} catch MoneiPayError.paymentTimeout {
    // MONEI Pay didn't respond in time
} catch {
    print("Payment failed: \(error.localizedDescription)")
}

API Reference

MoneiPay.acceptPayment(...)

Accepts an NFC payment via MONEI Pay.

Parameter Type Required Description
token String Yes Raw JWT auth token (no "Bearer " prefix)
amount Int Yes Amount in cents
description String? No Payment description
customerName String? No Customer name
customerEmail String? No Customer email
customerPhone String? No Customer phone
callbackUrl String? No HTTPS endpoint for the signed webhook. Trusted channel — use for fulfillment.
orderId String? No Merchant order reference. Surfaced in the webhook callback for reconciliation. Max 2048 chars. If omitted, the SDK generates one.
transactionType String? No Optional: SALE (default), AUTH, REFUND, CAPTURE, CANCEL, PAYOUT, VERIF. Server-validated.
completeScheme String Yes Your app's registered URL scheme. MONEI Pay opens <completeScheme>://payment-result on end
timeout TimeInterval? No Timeout in seconds (default: 60)

Returns PaymentResult. Throws MoneiPayError.

MoneiPay.handleCompleteRedirect(url:)

Handle incoming complete-redirect URL from MONEI Pay. Returns true if the URL was handled.

PaymentResult

Property Type Description
transactionId String Unique transaction ID
success Bool Whether payment was approved
amount Int? Amount in cents
cardBrand String? Card brand (visa, mastercard, etc.)
maskedCardNumber String? Masked card number (****1234)

MoneiPayError

Case Description
.moneiPayNotInstalled MONEI Pay not on device
.paymentInProgress Another payment is active
.paymentTimeout Callback not received in time
.paymentCancelled User cancelled
.paymentFailed(reason:) Payment declined or failed
.invalidParameters(_) Invalid input parameters (also INVALID_AMOUNT, INVALID_CALLBACK_URL, INVALID_COMPLETE_URL)
.failedToOpen Could not open MONEI Pay
.tokenExpired Auth token expired — fetch fresh token and retry
.invalidToken Auth token rejected
.notAuthenticated No signed-in session and no auth_token supplied
.accountNotConfigured Account is not set up for card-present payments

Example App

The examples/MerchantDemo directory contains a minimal SwiftUI app demonstrating the full integration flow: enter an API key, fetch a POS auth token, and accept an NFC payment via MONEI Pay.

To run:

  1. Open examples/MerchantDemo/MerchantDemo.xcodeproj in Xcode
  2. Set your Apple Development Team in Signing & Capabilities
  3. Build and run on a device with MONEI Pay installed

The demo references the SDK as a local Swift package (../../), so any local SDK changes are picked up immediately.

Beta: MONEI Pay for iOS is currently in beta. Join via TestFlight.

Token Generation

Your backend generates POS auth tokens via the MONEI API:

curl -X POST https://api.monei.com/v1/pos/auth-token \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json"

See the MONEI API docs for details.

Development

Maintainers: clone the repo, install Node dependencies with pnpm (pnpm install), then use swift build / swift test. Git commits are checked with commitlint via a Husky commit-msg hook. Releases use release-it (pnpm run release): it bumps the version, updates the changelog and MoneiPaySDK.podspec, creates a Git tag and GitHub release. Publishing to the CocoaPods trunk runs in CI when that release is published.

License

MIT