Integración de app iOS
Acepta pagos NFC desde tu app iOS usando el MoneiPaySDK. El SDK gestiona la construcción de la URL, el análisis de la redirección de finalización, los tiempos de espera y el manejo de errores.
Fuente: github.com/MONEI/monei-pay-ios-sdk
Utiliza esquemas de URL estándar — no se necesitan permisos especiales, certificados ni aprobaciones de Apple.
Cómo funciona
- Tu app llama a
MoneiPay.acceptPayment(...)con un token y un importe - El SDK abre MONEI Pay para la transacción NFC por contacto
- MONEI Pay redirige de vuelta a tu app con el resultado
- El SDK analiza la redirección de finalización y resuelve un
PaymentResult
Requisitos previos
- Cuenta MONEI
- iOS 15.0+, Swift 5.9+
- MONEI Pay instalado en el dispositivo
- Token de autenticación POS desde tu backend (consulta Primeros pasos)
Integración
1. Instala el SDK
- Swift Package Manager
- CocoaPods
En Xcode: File → Add Package Dependencies → introduce https://github.com/MONEI/monei-pay-ios-sdk → Up to Next Major Version desde 1.0.0.
O en Package.swift:
dependencies: [
.package(url: "https://github.com/MONEI/monei-pay-ios-sdk", from: "1.0.0")
]
pod 'MoneiPaySDK', :git => 'https://github.com/MONEI/monei-pay-ios-sdk.git', :tag => 'v1.0.0'
Ejecuta pod install y abre el .xcworkspace.
2. Configura Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>your-app</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>monei-pay</string>
</array>
Reemplaza your-app con el esquema de URL único de tu app (p. ej. tu bundle ID). Cada app de comercio debe usar un esquema diferente.
3. Conecta el gestor de finalización
- SwiftUI
- UIKit
import SwiftUI
import MoneiPaySDK
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
MoneiPay.handleCompleteRedirect(url: url)
}
}
}
}
import MoneiPaySDK
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return MoneiPay.handleCompleteRedirect(url: url)
}
4. Acepta un pago
import MoneiPaySDK
func acceptPayment() async {
do {
let result = try await MoneiPay.acceptPayment(
token: "eyJ...",
amount: 1500,
description: "Order #123",
customerName: "John Doe",
customerEmail: "john@example.com",
callbackUrl: "https://merchant.com/webhook/monei",
completeScheme: "your-app"
)
if result.success {
print("Payment approved: \(result.transactionId)")
print("Card: \(result.cardBrand ?? "") \(result.maskedCardNumber ?? "")")
}
} catch let error as MoneiPayError {
switch error {
case .moneiPayNotInstalled:
break
case .paymentCancelled:
break
case .paymentTimeout:
break
case .tokenExpired, .invalidToken:
break
case .notAuthenticated, .accountNotConfigured:
break
case .paymentFailed(let reason):
print("Payment failed: \(reason ?? "unknown")")
default:
print("Error: \(error.localizedDescription)")
}
}
}
callbackUrl es un webhook firmado de confianza entregado de servidor a servidor — úsalo para completar pedidos. completeScheme (y la complete_url resultante) es solo una redirección del lado del cliente — devuelve al usuario a tu app pero no está firmada. Consulta Entrega de resultados para más detalles.
Referencia del SDK
MoneiPay.acceptPayment(...)
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
token | String | Sí | Token de autenticación POS (JWT en bruto, sin prefijo "Bearer ") |
amount | Int | Sí | Importe del pago en céntimos (p. ej. 1500 = 15,00 EUR) |
description | String? | No | Descripción del pago |
customerName | String? | No | Nombre del cliente |
customerEmail | String? | No | Correo electrónico del cliente |
customerPhone | String? | No | Teléfono del cliente |
callbackUrl | String? | No | URL del webhook firmado de confianza. Debe ser https:// estricto, máx. 2048 caracteres. Consulta Entrega de resultados. |
orderId | String? | No | Referencia de pedido del comercio. Configúralo para que aparezca en el webhook de callback para la conciliación con tu pedido POS. Máx. 2048 caracteres. Si se omite, MONEI genera uno. |
transactionType | String? | No | Tipo de transacción opcional: SALE (por defecto), AUTH, REFUND, CAPTURE, CANCEL, PAYOUT, VERIF. Validado en el servidor; los valores no válidos son rechazados. |
completeScheme | String | Sí | Esquema de URL registrado de tu app — usado para redirigir al usuario de vuelta tras completar el pago |
timeout | TimeInterval? | No | Tiempo de espera en segundos (por defecto: 60) |
PaymentResult
| Propiedad | Tipo | Descripción |
|---|---|---|
transactionId | String | ID de transacción de MONEI |
success | Bool | Indica si el pago fue aprobado |
amount | Int? | Importe del pago en céntimos |
cardBrand | String? | Marca de la tarjeta (p. ej. visa, mastercard) |
maskedCardNumber | String? | Número de tarjeta enmascarado (p. ej. ****1234) |
Tipos de error
| Error | Descripción |
|---|---|
moneiPayNotInstalled | MONEI Pay no está instalado |
paymentInProgress | Otro pago ya está activo |
paymentTimeout | Sin respuesta dentro del tiempo de espera |
paymentCancelled | El usuario canceló |
paymentFailed(reason:) | Pago rechazado o fallido |
invalidParameters(_:) | Entrada no válida (p. ej. importe no positivo, callbackUrl o complete_url mal formados) |
tokenExpired | El token de autenticación POS ha expirado (>24h) |
invalidToken | El token de autenticación POS está mal formado o firmado con la clave incorrecta |
notAuthenticated | No hay token POS y el usuario no ha iniciado sesión en MONEI Pay |
accountNotConfigured | La cuenta de MONEI Pay no tiene la configuración POS requerida |
failedToOpen | No se pudo abrir MONEI Pay |
Integración manual (esquema de URL)
Si prefieres no usar el SDK, puedes integrarte directamente mediante esquemas de URL.
Mostrar integración manual con esquema de URL
Abre la URL de pago
func acceptPayment(amountInCents: Int) {
var components = URLComponents(string: "monei-pay://accept-payment")!
components.queryItems = [
URLQueryItem(name: "amount", value: String(amountInCents)),
URLQueryItem(name: "auth_token", value: "eyJ..."),
URLQueryItem(name: "callback_url", value: "https://merchant.com/webhook/monei"),
URLQueryItem(name: "complete_url", value: "your-app://payment-result")
]
guard let url = components.url else { return }
UIApplication.shared.open(url)
}
Gestiona la redirección de finalización
struct PaymentResult {
let success: Bool
let transactionId: String?
let amount: String?
let cardBrand: String?
let maskedCardNumber: String?
let error: String?
init(from url: URL) {
let params = URLComponents(url: url, resolvingAgainstBaseURL: false)?
.queryItems?
.reduce(into: [String: String]()) { $0[$1.name] = $1.value } ?? [:]
self.success = params["success"] == "true"
self.transactionId = params["transaction_id"]
self.amount = params["amount"]
self.cardBrand = params["card_brand"]
self.maskedCardNumber = params["masked_card_number"]
self.error = params["error"]
}
}
Los parámetros de consulta en la redirección de complete_url no están firmados — pueden suplantarse. Usa callback_url (webhook firmado) o Obtener pago para confirmar el resultado real antes de completar un pedido. Consulta Entrega de resultados.
Parámetros de la URL
Parámetros de la solicitud
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | Integer | Sí | Importe del pago en céntimos (p. ej. 1500 = 15,00 EUR) |
auth_token | String | Sí | Token de autenticación POS (JWT en bruto) |
callback_url | String | No | URL del webhook firmado de confianza. Debe ser https:// estricto, máx. 2048 caracteres. Recibe un POST firmado con HMAC MONEI-Signature al completar. |
complete_url | String | No | URL que se abre en el dispositivo tras completarse el pago. Acepta https://, esquemas de URL personalizados, Universal Links. Máx. 2048 caracteres. No firmada. |
description | String | No | Descripción del pago |
customer_name | String | No | Nombre del cliente |
customer_email | String | No | Correo electrónico del cliente |
customer_phone | String | No | Teléfono del cliente |
order_id | String | No | Referencia de pedido del comercio. Aparece en el webhook de callback para la conciliación. Máx. 2048 caracteres. Si se omite, MONEI genera uno. |
transaction_type | String | No | Tipo de transacción opcional: SALE, AUTH, REFUND, CAPTURE, CANCEL, PAYOUT, VERIF. Validado en el servidor. |
Parámetros de redirección de complete_url (éxito)
| Parámetro | Tipo | Descripción |
|---|---|---|
success | String | "true" |
transaction_id | String | ID de transacción de MONEI |
amount | String | Importe del pago en céntimos |
card_brand | String | Marca de la tarjeta (p. ej. visa, mastercard) |
masked_card_number | String | Número de tarjeta enmascarado (p. ej. ****1234) |
Parámetros de redirección de complete_url (error)
| Parámetro | Tipo | Descripción |
|---|---|---|
success | String | "false" |
error | String | Código de error — consulta lista de códigos de error |
App de ejemplo
El directorio examples/MerchantDemo contiene una app SwiftUI que demuestra el flujo completo. Abre MerchantDemo.xcodeproj, configura tu equipo de firma y ejecútala en un dispositivo físico con MONEI Pay instalado. El proyecto referencia el SDK como paquete local, por lo que los cambios en el SDK se aplican de inmediato.
Resolución de problemas
moneiPayNotInstalled
MONEI Pay debe estar instalado en el dispositivo. Instálalo desde el App Store.
failedToOpen
Verifica que monei-pay aparece en LSApplicationQueriesSchemes en tu Info.plist. Sin ello, iOS bloquea la comprobación canOpenURL.
paymentTimeout
El tiempo de espera por defecto es de 60 segundos. Auméntalo mediante el parámetro timeout si es necesario. El temporizador usa tiempo de reloj real — poner tu app en segundo plano no lo pausa.
La redirección de finalización no se recibe
Comprueba que tu esquema de URL está registrado en CFBundleURLTypes en Info.plist y que MoneiPay.handleCompleteRedirect(url:) se llama en onOpenURL (SwiftUI) o en application(_:open:options:) (UIKit). Consulta Conecta el gestor de finalización.
El pago funciona en el simulador pero no en el dispositivo
Los pagos NFC requieren un dispositivo físico con MONEI Pay instalado. Los simuladores no son compatibles.