Saltar al contenido principal

Integración de app Android

Acepta pagos NFC desde tu app Android usando el SDK de Android de MONEI Pay. El SDK gestiona el lanzamiento de intents, el análisis de resultados y el manejo de errores.

Fuente: github.com/MONEI/monei-pay-android-sdk

No se requiere firma especial

Utiliza intents estándar de Android — no se necesitan firmas especiales, permisos ni aprobaciones de plataforma.

Modos de pago

El SDK admite dos modos:

  • Directo (PaymentMode.DIRECT) — Lanza CloudCommerce directamente. No se requiere MONEI Pay.
  • A través de MONEI Pay (PaymentMode.VIA_MONEI_PAY) — Lanza MONEI Pay, que gestiona el pago NFC.
DirectoA través de MONEI Pay
Token de autenticación POSObligatorioObligatorio
App MONEI PayNo necesariaObligatoria
App CloudCommerceObligatoriaNo obligatoria
Ideal paraConfiguraciones solo CloudCommerceFlujo completo del comercio MONEI Pay

Descarga las apps necesarias

MONEI Pay (modo a través de MONEI Pay)

Descarga MONEI Pay en Google Play

CloudCommerce (modo directo)

Descarga CloudCommerce en Google Play

Requisitos previos

Integración

1. Añade la dependencia

Requiere un PAT con read:packages (o GITHUB_TOKEN en CI):

gradle.properties
gpr.user=YOUR_GITHUB_USERNAME
gpr.key=YOUR_GITHUB_TOKEN
settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/MONEI/monei-pay-android-sdk")
credentials {
username = providers.gradleProperty("gpr.user")
.orElse(providers.environmentVariable("GITHUB_ACTOR"))
.get()
password = providers.gradleProperty("gpr.key")
.orElse(providers.environmentVariable("GITHUB_TOKEN"))
.get()
}
}
}
}
app/build.gradle.kts
dependencies {
implementation("com.monei:monei-pay-sdk:1.0.0")
}

2. Configura AndroidManifest

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<queries>
<intent>
<action android:name="com.monei.pay.ACCEPT_PAYMENT" />
</intent>
<package android:name="com.mastercard.cpos" />
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="cloud_payment" />
</intent>
</queries>

</manifest>

3. Acepta un pago

import com.monei.pay.sdk.MoneiPay
import com.monei.pay.sdk.PaymentMode
import com.monei.pay.sdk.MoneiPayException

try {
val result = MoneiPay.acceptPayment(
context = this,
token = "eyJ...",
amount = 1500,
description = "Order #123",
customerName = "John Doe",
customerEmail = "john@example.com",
customerPhone = "+34600000000",
callbackUrl = "https://merchant.com/webhook/monei",
mode = PaymentMode.DIRECT
)

if (result.success) {
println("Payment approved: ${result.transactionId}")
println("Card: ${result.cardBrand} ${result.maskedCardNumber}")
}
} catch (e: MoneiPayException.CloudCommerceNotInstalled) {
// Prompt user to install CloudCommerce
} catch (e: MoneiPayException.PaymentCancelled) {
// User cancelled
} catch (e: MoneiPayException.InvalidToken) {
// Token expired or invalid
} catch (e: MoneiPayException.PaymentFailed) {
println("Payment failed: ${e.reason}")
} catch (e: MoneiPayException) {
println("Error: ${e.message}")
}
Modelo de confianza

callbackUrl es un webhook firmado de confianza entregado de servidor a servidor — úsalo para completar pedidos. El PaymentResult síncrono del SDK también es de confianza porque vuelve a través del sistema de intents de Android desde la app de pago de origen, pero igualmente debe conciliarse mediante el webhook o Obtener pago para el registro. Consulta Entrega de resultados.

Referencia del SDK

MoneiPay.acceptPayment(...)

Función suspendida — llámala desde un ámbito de corrutina.

ParámetroTipoObligatorioDescripción
contextContextContexto de Activity o Application
tokenStringToken JWT de autenticación en bruto (sin prefijo "Bearer ")
amountIntImporte en céntimos
descriptionString?NoDescripción del pago
customerNameString?NoNombre del cliente
customerEmailString?NoCorreo electrónico del cliente
customerPhoneString?NoTeléfono del cliente
callbackUrlString?NoURL del webhook firmado de confianza. Debe ser https:// estricto, máx. 2048 caracteres. Consulta Entrega de resultados.
orderIdString?NoReferencia de pedido del comercio. Aparece en el webhook de callback para la conciliación. Máx. 2048 caracteres. Si se omite, el SDK genera uno.
transactionTypeString?NoTipo de transacción opcional: SALE (por defecto), AUTH, REFUND, CAPTURE, CANCEL, PAYOUT, VERIF. Validado en el servidor.
modePaymentModeNoDIRECT (por defecto) o VIA_MONEI_PAY

PaymentResult

PropiedadTipoDescripción
transactionIdStringID de transacción de MONEI
successBooleanIndica si el pago fue aprobado
amountInt?Importe del pago en céntimos
cardBrandString?Marca de la tarjeta (p. ej. visa, mastercard)
maskedCardNumberString?Número de tarjeta enmascarado (p. ej. ****1234)

Tipos de error

ExcepciónDescripción
MoneiPayNotInstalledMONEI Pay no está instalado (modo VIA_MONEI_PAY)
CloudCommerceNotInstalledCloudCommerce no está instalado (modo DIRECT)
PaymentInProgressOtro pago ya está activo
PaymentCancelledEl usuario canceló
PaymentFailedPago rechazado o fallido (tiene reason)
InvalidParametersEntrada no válida (p. ej. importe no positivo)
InvalidTokenToken de autenticación no válido o expirado

Integración manual (Intent)

Para integración sin el SDK usando intents de Android directamente.

Mostrar integración manual con intent

Configura tu Manifest

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="com.monei.pay.permission.ACCEPT_PAYMENT" />

<queries>
<intent>
<action android:name="com.monei.pay.ACCEPT_PAYMENT" />
</intent>
</queries>

</manifest>

Lanza el intent de pago

class MainActivity : AppCompatActivity() {

private val paymentLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
when (result.resultCode) {
RESULT_OK -> handleSuccess(result.data)
RESULT_CANCELED -> handleError(result.data)
}
}

fun acceptPayment(amountInCents: Int) {
val intent = Intent("com.monei.pay.ACCEPT_PAYMENT").apply {
setPackage("com.monei.moneibusiness")
putExtra("amount_cents", amountInCents)
putExtra("auth_token", "eyJ...")
}

if (intent.resolveActivity(packageManager) == null) {
return
}

paymentLauncher.launch(intent)
}
}

Gestiona el resultado

private fun handleSuccess(data: Intent?) {
val success = data?.getBooleanExtra("success", false) ?: false
val transactionId = data?.getStringExtra("transaction_id")
val amount = data?.getIntExtra("amount", 0)
val cardBrand = data?.getStringExtra("card_brand")
val maskedCard = data?.getStringExtra("masked_card_number")
}

private fun handleError(data: Intent?) {
val errorCode = data?.getStringExtra("error_code") ?: "UNKNOWN"
val errorMessage = data?.getStringExtra("error_message") ?: "Payment failed"
}

Parámetros del intent

Extras de la solicitud

ExtraTipoObligatorioDescripción
amount_centsIntImporte del pago en céntimos (p. ej. 1500 = 15,00 EUR)
auth_tokenStringToken de autenticación POS (JWT en bruto)
descriptionStringNoDescripción del pago
customer_nameStringNoNombre del cliente
customer_emailStringNoCorreo electrónico del cliente
customer_phoneStringNoTeléfono del cliente

Extras del resultado (RESULT_OK)

ExtraTipoDescripción
transaction_idStringID de transacción de MONEI
successBooleantrue si aprobado, false si rechazado
amountIntImporte del pago en céntimos
card_brandStringMarca de la tarjeta (p. ej. visa, mastercard)
masked_card_numberStringNúmero de tarjeta enmascarado (p. ej. ****1234)

Extras del resultado (RESULT_CANCELED)

ExtraTipoDescripción
error_codeStringCódigo de error (p. ej. PAYMENT_FAILED, NOT_AUTHENTICATED)
error_messageStringDescripción del error legible por personas

Para llamadores que no son Android — incluidas apps web (terminales de comercio basadas en navegador) — MONEI Pay acepta un deep link con la misma estructura que el esquema de URL de iOS. Consulta Integración de app web para el flujo completo desde el navegador.

Mostrar integración manual con deep link

Abre la URL de pago

<a
href="monei-pay://accept-payment
?amount=1500
&auth_token=eyJ...
&callback_url=https://merchant.com/webhook/monei
&complete_url=https://merchant.com/checkout/done"
>
Pay with MONEI Pay
</a>

O de forma programática:

window.location.href =
'monei-pay://accept-payment' +
'?amount=1500' +
'&auth_token=' +
encodeURIComponent(token) +
'&callback_url=' +
encodeURIComponent('https://merchant.com/webhook/monei') +
'&complete_url=' +
encodeURIComponent('https://merchant.com/checkout/done');

Android resuelve monei-pay:// a través de la app MONEI Pay instalada. El usuario pulsa el enlace (o el navegador lo abre), MONEI Pay gestiona el pago NFC y luego redirige a complete_url con el resultado.

Parámetros de la URL

ParámetroTipoObligatorioDescripción
amountIntegerImporte del pago en céntimos (p. ej. 1500 = 15,00 EUR)
auth_tokenStringToken de autenticación POS (JWT en bruto)
callback_urlStringNoURL del webhook firmado de confianza. Debe ser https:// estricto, máx. 2048 caracteres. Recibe un POST firmado con HMAC MONEI-Signature al completar.
complete_urlStringNoURL que se abre en el dispositivo tras completarse el pago. Acepta https://, esquemas de URL personalizados, App Links. Máx. 2048 caracteres. No firmada.
descriptionStringNoDescripción del pago
customer_nameStringNoNombre del cliente
customer_emailStringNoCorreo electrónico del cliente
customer_phoneStringNoTeléfono del cliente
order_idStringNoReferencia 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_typeStringNoTipo 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ámetroTipoDescripción
successString"true"
transaction_idStringID de transacción de MONEI
amountStringImporte del pago en céntimos
card_brandStringMarca de la tarjeta (p. ej. visa, mastercard)
masked_card_numberStringNúmero de tarjeta enmascarado (p. ej. ****1234)

Parámetros de redirección de complete_url (error)

ParámetroTipoDescripción
successString"false"
errorStringCódigo de error — consulta lista de códigos de error
Modelo de confianza

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.

App de ejemplo

El directorio examples/merchant-demo/ contiene una app mínima que demuestra el flujo completo. Ejecuta ./gradlew assembleDebug e instálala en un dispositivo compatible con NFC. El proyecto usa includeBuild para referenciar el SDK localmente, por lo que los cambios en el SDK se aplican de inmediato.

Resolución de problemas

CloudCommerceNotInstalled

CloudCommerce es una app independiente de MONEI Pay. Instálala desde Google Play y verifica que tu manifest incluya el <package> y el esquema cloud_payment:// en <queries>.

MoneiPayNotInstalled

Instala MONEI Pay desde Google Play. Verifica que tu manifest incluya la acción com.monei.pay.ACCEPT_PAYMENT en <queries>.

InvalidToken

El token de autenticación POS tiene una validez de 24h. Genera un token nuevo desde tu backend. Pasa la cadena JWT en bruto — no "Bearer ...".

El pago falla en API 30+

Android 11+ requiere <queries> para la visibilidad de paquetes. Asegúrate de que tu manifest tiene el bloque completo de queries de Configurar AndroidManifest.

La resolución de dependencias falla

  • JitPack: Añade google(), mavenCentral() y https://jitpack.io a settings.gradle.kts bajo dependencyResolutionManagement.
  • GitHub Packages: Comprueba gpr.user / gpr.key en gradle.properties y el bloque de repositorio maven.pkg.github.com/MONEI/monei-pay-android-sdk.