Integrar App-to-App Verification (A2A)
Verifica la identidad de tu cliente aprovechando la verificación que realiza tu propia app, evitando pasos extras como el OTP vía SMS o mail.
Introducción
Cuando tu cliente agrega una tarjeta a Apple Pay o a Google Wallet, no siempre alcanza con lo que ingresó: la wallet necesita confirmar que es realmente el titular antes de activar el token. A este paso adicional lo llamamos Yellow Path, y por defecto tu cliente lo resuelve con un código de un solo uso que le enviamos por SMS o email.
Con App-to-App Verification (A2A), esa verificación sucede dentro de tu propia app, con tu login y tu biometría, en lugar de un OTP externo. La wallet invoca tu app directamente, tu cliente confirma su identidad con el mismo mecanismo que ya usa todos los días y activas el token llamando a nuestra API. El resultado es menos fricción, menos abandono en el Yellow Path y control total sobre la experiencia de seguridad.
Además, al no depender de un SMS o un email, te ahorras el costo de cada envío: la autenticación ocurre enteramente dentro de tu app.
Funcionamiento
- Tu cliente agrega su tarjeta directamente a Apple Pay o Google Wallet.
- Verificamos la información de la tarjeta y determinamos que hace falta confirmar la identidad de tu cliente antes de activar el token (Yellow Path).
- Como registraste A2A como método de autenticación, la wallet invoca tu app para que tu cliente se verifique ahí mismo. La forma de invocación depende de la wallet:
- Google Wallet invoca tu app con un Intent explícito y te envía el payload de Visa codificado en Base64URL.
- Apple Pay le ofrece a tu cliente verificarse dentro de tu app. Si tu cliente elige esa opción en el momento, Apple Pay abre tu app usando el deep link que configuraste y te envía parámetros para identificar el pass pendiente de activación. Si en cambio abre tu app más tarde por su cuenta, tu app tiene que consultarle a Apple Pay si hay alguna tarjeta pendiente de activación.
- Tu app valida que quien la invocó sea efectivamente la wallet correspondiente y autentica a tu cliente con tu login o biometría.
- Tu app muestra la tarjeta pendiente de activar y, cuando tu cliente confirma, llama a nuestra API para activar el token.
- Se completa la tokenización, aunque la forma de cerrar el flujo también depende de la wallet:
- En Google Wallet, tu app tiene que devolver explícitamente el resultado (aprobado, rechazado o fallido) para que la wallet retome el flujo.
- En Apple Pay, detectamos que el token quedó activo y completamos la tokenización sin que tengas que devolver ningún resultado.
Habilitación con Pomelo
Antes de escribir código, completa este formulario indicando los datos que correspondan según la wallet que estés integrando:
| Wallet | Datos a incluir en el formulario |
|---|---|
| Google Wallet | - Package name de tu aplicación (com.issuer.issuerApp).- Listado de tarjetas para tu whitelist de pruebas. |
| Apple Pay | - Adam ID de tu app en App Store Connect (por ejemplo, 1234567890).- App ID combinando tu Team ID y tu Bundle ID (por ejemplo, 1234ABCD.com.issuer.issuerApp).- URL scheme (deep-link) con el que tu app va a recibir a Apple Pay (por ejemplo, miapp://inapp-verification).- Listado de tarjetas para tu whitelist de pruebas. |
A2A no está disponible en Stage: las pruebas se hacen directamente en producción, por eso necesitamos la whitelist. Mientras esté activa, la wallet solo le ofrece este método a esas tarjetas puntuales; el resto de tus clientes sigue resolviendo el Yellow Path con SMS OTP o Email OTP.
Implementación
1. Declara el intent-filter en tu AndroidManifest.xml
Visa define un formato fijo para el service que Google Wallet busca: {tu package name}.a2a. Declara la acción en la activity que va a recibir la verificación.
2. Arma la activity que recibe el intent
Google Wallet te envía el payload de Visa en Intent.EXTRA_TEXT, como un JSON codificado en Base64URL. Decodifícalo apenas arranca la activity.
Estos son los campos que Visa incluye en el payload:
| Campo | Descripción |
|---|---|
| panReferenceID | Identificador único del PAN. |
| tokenRequestorID | Identificador de tu Token Requestor. |
| tokenReferenceID | Identificador del token, distinto del que recibe la wallet pero consistente con el que ya recibiste en tus mensajes de emisor. |
| panLast4 | Últimos 4 dígitos de la tarjeta que hay que autenticar. |
| deviceID | Identificador estable del dispositivo, definido por la wallet. |
| walletAccountID | Identificador de tu cliente dentro de la wallet. |
3. Valida el caller y aplica tu capa de seguridad
Antes de mostrar cualquier dato, confirma que quien invocó tu activity fue efectivamente Google Wallet (Google Play Services).
La autenticación de tu cliente queda completamente a tu criterio de seguridad. No te imponemos un método particular: puedes pedir login con contraseña, biometría, PIN o el factor que ya uses en el resto de tu app. Si tu cliente cancela o falla la autenticación, no llames a nuestra API y devuelve el resultado como se explica en el paso 6.
4. Muestra la tarjeta y la acción de activar
Una vez autenticado tu cliente, muestra la tarjeta que Visa identificó (panLast4) y una acción para confirmar la activación.
5. Llama a nuestra API para activar el token
Cuando tu cliente confirma, llama al endpoint Activate token usando el tokenReferenceID del payload como identificador del token y motive con el valor APP_TO_APP_ACTIVATION.
| Campo | Descripción | Ejemplo |
|---|---|---|
| tokenId | Identificador del token a activar. Usa el tokenReferenceID que recibiste en el payload. | DNITHE381502386342002358 |
| motive | Motivo de la activación. Para este flujo, siempre APP_TO_APP_ACTIVATION. | APP_TO_APP_ACTIVATION |
Si la respuesta es exitosa, activamos el token del lado de Visa sin que tengas que devolver ningún código de autenticación adicional.
6. Maneja el resultado
Devuelve el control a Google Wallet indicando si la verificación fue aprobada, rechazada o falló.
Valor de STEP_UP_RESPONSE | Cuándo usarlo |
|---|---|
approved | Autenticaste a tu cliente y activamos el token exitosamente. |
declined | Tu cliente canceló la autenticación o eligió no continuar. |
failure | Ocurrió un error técnico (autenticación fallida, error de red, timeout). |
Pruebas con Android Debug Bridge (adb)
Puedes simular el intent que envía Google Wallet usando adb para probar el manejo del intent de forma aislada, sin depender de un flujo end-to-end real.
Primero, codifica un payload de ejemplo en Base64URL:
Usa el resultado como valor de EXTRA_TEXT en el comando de adb:
Si el comando funciona, se abre tu activity. Si falla, el error suele indicar que no se encontró la activity, lo que apunta a un mismatch entre la acción o el package name declarados en el manifest y los que usaste en el comando.
Repositorio de ejemplo
Para complementar esta guía, te compartimos un repositorio de ejemplo con una implementación de punta a punta de A2A para Google Wallet.
Puedes usarlo como referencia para entender cómo se conecta la verificación de identidad con la activación del token.
Repositorio: example-android-app-google-upp
1. Detecta passes pendientes de activación
En la terminología de Apple, un pass es el certificado digital que representa la tarjeta dentro de Apple Pay.
Tu app tiene que manejar dos formas de entrada:
- Sincrónica: cuando Apple Pay abre tu app durante el flujo de agregado de tarjeta.
- Asincrónica: cuando tu cliente abre tu app más tarde para completar la activación.
Veamos de qué se trata cada una:
Verificación sincrónica
Tu cliente elige verificarse en el momento, desde Apple Pay. Apple Pay abre tu app usando el deep link que nos compartiste durante la habilitación y agrega parámetros para que puedas identificar qué pass intenta activar tu cliente.
| Parámetro | Ejemplo de valor | Para qué se utiliza |
|---|---|---|
| action | verify | Identifica que el deep link corresponde a una verificación de Apple Pay. |
| serialNumber | nc.prod.pod8_dfcd46c9e063428f829dbe4a0564813e | Identifica el pass específico que tienes que verificar. |
| passTypeIdentifier | paymentpass.com.apple | Identifica el tipo de pass. Para tarjetas de pago, el valor esperado es paymentpass.com.apple. |
Con passTypeIdentifier y serialNumber, puedes resolver el pass correspondiente usando PassKit.
//, por ejemplo miapp:inapp-verification.
Verificación asincrónica
Tu cliente puede abandonar el flujo después de agregar la tarjeta a Apple Pay y abrir tu app más tarde, sin pasar por Apple Pay. En ese caso, tu app no recibe parámetros en el deep link y tiene que consultar PassKit para identificar passes pendientes de activación.
Para iOS 13.4 o superior y watchOS 6.2 o superior, usa passes() para buscar passes en el iPhone y remoteSecureElementPasses para buscar passes en Apple Watch. Luego, filtra los passes cuyo estado de activación sea requiresActivation.
2. Autentica a tu cliente y valida que el pass le pertenezca
La autenticación de tu cliente queda completamente a tu criterio de seguridad. No te imponemos un método particular: puedes pedir login con contraseña, biometría, PIN o el factor que ya uses en el resto de tu app.
Antes de mostrar cualquier pass pendiente de activación, confirma que pertenece al usuario autenticado. Para eso, cruza la información del pass con las tarjetas asociadas a ese usuario en tu backend.
3. Muestra la acción de activación
Después de autenticar a tu cliente y validar la titularidad del pass, muestra la tarjeta pendiente de activar. Si hay más de un pass pendiente, puedes mostrar una lista para que tu cliente elija cuál activar.
Apple recomienda indicar el dispositivo donde la tarjeta requiere activación, por ejemplo iPhone o Apple Watch.
4. Llama a nuestra API para activar el token
Cuando tu cliente confirma la activación, tu app le pide a tu backend activar el pass seleccionado. Luego, tu backend llama al endpoint Activate token usando el identificador de cuenta de dispositivo (deviceAccountIdentifier) del pass como identificador del token, y motive con el valor APP_TO_APP_ACTIVATION.
Si tu cliente cancela o falla la autenticación, no llames al endpoint Activate token.
| Campo | Descripción | Ejemplo |
|---|---|---|
| tokenId | Identificador del token a activar. Usa el deviceAccountIdentifier del pass, no el número de serie que te mandó Apple Pay. | DNITHE381502386342002358 |
| motive | Motivo de la activación. Para este flujo, siempre APP_TO_APP_ACTIVATION. | APP_TO_APP_ACTIVATION |
Cuando la activación termina correctamente, confirma el resultado dentro de tu app. Tu cliente permanece en la app emisora y no tienes que devolverle una respuesta a Apple Pay.
Preguntas frecuentes
¿Tengo que hacer una certificación o gestión nueva con Apple o Google para integrar A2A?
No. No es necesario involucrar a Apple ni a Google en el proceso de integración: A2A se configura a través de tu bandera y de Pomelo, con los pasos que describimos en esta guía, más allá del proceso de Apple Pay o Google Wallet que ya completaste.
¿Qué pasa si mi cliente cancela la autenticación o falla la biometría?
No llames a nuestra API de activación. En Google Wallet, además, devuelve declined o failure en STEP_UP_RESPONSE. Tu cliente puede retomar la verificación la próxima vez que abra la wallet o tu app.
¿Qué pasa si mi app no está instalada en el dispositivo?
La wallet lleva a tu cliente a la ficha de tu app en la tienda correspondiente (App Store o Play Store). Una vez instalada, tiene que reiniciar el flujo de agregado de tarjeta desde Apple Pay o Google Wallet.
¿Dónde encuentro la documentación oficial?
En la guía de In-App Verification de Apple y en la guía de App-to-app verification de Google. Ahí vas a encontrar el detalle completo del contrato de cada wallet, los requisitos de configuración y las dos formas de activar un token.