Integración 3DS API + librería kushki.js

Si tienes una integración por API (backend) y requieres autenticar pagos mediante 3D Secure, es necesario implementar cualquiera de las bibliotecas frontend Kushki.js o Kushki.js Hosted Fields para inicializar el servicio de 3D Secure y posteriormente desplegar el modal de autenticación, en caso de que sea requerido.

Transacciones soportadas con esta opción

Soporta ✅No soporta ⛔️
Autenticación 3DS para cargos únicos con tarjeta
Autenticación 3DS para preautorizaciones

Paso 1. Obtén un Json Web Token (JWT)

Es necesario implementar el método requestSecureInit() desde Kushki.js o Kushki.js Hosted Fields para obtener un Json Web Token (JWT), el cual será necesario al momento de generar un token.

Kushki.js

Usa Kushki.js si necesitas un mayor control sobre el “look & feel” o apariencia de tu formulario de pago.

Importa Kushki.js

Puedes importar la biblioteca de Kushki.js a través de CDN o como un paquete NPM.

Opción 1 - CDN

Usa el siguiente tag script al final del <body> en tu página de pagos.

<script src="https://cdn.kushkipagos.com/kushki.min.js"></script>
Opción 2 - NPM

Instala el paquete desde npm.

npm install --save @kushki/js

Luego impórtalo en tu código utilizando el siguiente código.

import { Kushki } from “@kushki/js”;

Configura el objeto Kushki

Añade el siguiente código a tu aplicación

const kushki = new Kushki({
merchantId: 'public-merchant-id', // Your public merchant id
inTestEnvironment: true,
});

Recoge la información del usuario y envíala a tu back-end

Primero, añade el formulario a tu página de pagos con los campos requeridos. Puedes diseñarlo de la forma que mejor te parezca.

Por ejemplo:

<form id="payment-form">
<input placeholder="Card Number" type="text" name="number">
<input placeholder="Full Name" type="text" name="name">
<input placeholder="MM" type="text" name="expiry_month">
<input placeholder="YY" type="text" name="expiry_uear">
<input placeholder="CVC" type="text" name="cvc">
<button id="submit">Pay $49.99</button>
</form>

Consume el método requestSecureInit()

Usa el método requestSecureInit() enviando el número de la tarjeta, para obtener el jwt.

var callback = function(response) {
if(!response.code){
console.log(response);
} else {
console.error('Error: ',response.error, 'Code: ', response.code, 'Message: ',response.message);
}
}
kushki.requestSecureInit({
card: {
number: "4000000000000002"
}
}, callback);

Si la solicitud ha sido exitosa, se regresará un objeto json con el jwt:

{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTQ2NTY4ODYsImlhdCI6MTY1NDY0OTY4NiwiaXNzIjoiNWVhMzJmZDJmZjQ2NDU2OTY3YjUyNDliIiwianRpIjoiMDFhZTQyYWUtYzMyZS00YWRjLWFmOWQtZWVhMmFlNjRkMDkxIiwiT3JnVW5pdElkIjoiNWVhMzJmZDJhZDA3ZDIxYTM2OTc4OGFlIiwiUmVmZXJlbmNlSWQiOiI3ZjY1NzM5NS0yMDIwLTQ1ZjEtOTY4Mi05MzJiNTU5YWYzMWIifQ.JUkk70Kg4KlUYW7eIvsW8LoDhxJeG8P00VrJH9oQipc"
}

En caso contrario, te arrojará la siguiente respuesta de error:

{
"mensaje" : "mensaje de error" ,
"código" : "código de error" ,
"error" : "mensaje de error"
}

Kushki.js Hosted Fields

Con Hosted Fields, incluido en Kushki.js, podrás recolectar de forma segura la información de pago del cliente a través de campos almacenados en infraestructura de Kushki. Devuelve un token el cual permite continuar con el flujo de pago desde el back-end.

Importa Kushki.js Hosted Fields en tu aplicación

Opción 1 - CDN

Importa la biblioteca de Kushki.js Hosted Fields en tu aplicación a través de una etiqueta <script> dentro de la etiqueta <body>. Una vez importada, podrás acceder a los recursos descritos más adelante para crear un flujo de pago con Kushki.

Es necesario importar la biblioteca kushki.min.js (la cuál trae el código necesario para almacenar las credenciales de tu comercio) y la biblioteca antifraud.min.js (la cuál trae las herramientas necesarias para poder realizar autenticaciones de seguridad).

Opción 1 - CDN
<script src="https://cdn.kushkipagos.com/js/latest/kushki.min.js"></script>
<script src="https://cdn.kushkipagos.com/js/latest/antifraud.min.js"></script>
Opción 2 - NPM

Instala la biblioteca Kushki.js Hosted Fields como un paquete npm dentro de tu aplicación con el siguiente código:

npm install --save @kushki/js-sdk
Opción 3 - YARN

Instala la biblioteca Kushki.js Hosted Fields como un paquete yarn dentro de tu aplicación con el siguiente código:

yarn install @kushki/js-sdk

Crea una instancia de KushkiOptions

Para hacer uso de la biblioteca Kushki.js Hosted Fields, es necesario primero crear una instancia de tipo KushkiOptions la cuál te permite declarar la clave pública del comercio así como poder seleccionar el ambiente (prueba o producción) mediante el método init().

Añade el siguiente código a tu aplicación:

import { IKushki, init, KushkiError } from "@kushki/js-sdk";
const kushkiOptions : KushkiOptions = {
publicCredentialId: '<public-credential-id>', // This corresponds to the public credential of the merchant
inTest: true
};
const buildKushkiInstance = async () => {
try {
const kushkiInstance : Ikushki = await init(kushkiOptions);
} catch (e: KushkiError) {
console.error(e.message);
}
}

Revisa la referencia para más información sobre la instancia KushkiOptions.

Inicializa el servicio de autenticación por 3D Secure

Consume el método requestSecureInit() enviando el número de tarjeta para obtener un JWT.

import { init, IKushki } from "@kushki/js-sdk";
import { requestSecureInit, SecureInitRequest, SecureInitResponse } from "@kushki/js-sdk/Antifraud";
const onRequestSecureInit = async () => {
try {
const kushkiInstance: IKushki = await init({
inTest: true,
publicCredentialId: merchantId
});
const secureInitRequest: SecureInitRequest = {
card: {
number: cardNumber
}
};
const secureInitResponse: SecureInitResponse = await requestSecureInit(
kushkiInstance,
secureInitRequest
);
console.log(secureInitResponse);
} catch (error: any) {
console.log(error)
}
};

Si la solicitud ha sido exitosa, se regresará un objeto json con el jwt:

{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTQ2NTY4ODYsImlhdCI6MTY1NDY0OTY4NiwiaXNzIjoiNWVhMzJmZDJmZjQ2NDU2OTY3YjUyNDliIiwianRpIjoiMDFhZTQyYWUtYzMyZS00YWRjLWFmOWQtZWVhMmFlNjRkMDkxIiwiT3JnVW5pdElkIjoiNWVhMzJmZDJhZDA3ZDIxYTM2OTc4OGFlIiwiUmVmZXJlbmNlSWQiOiI3ZjY1NzM5NS0yMDIwLTQ1ZjEtOTY4Mi05MzJiNTU5YWYzMWIifQ.JUkk70Kg4KlUYW7eIvsW8LoDhxJeG8P00VrJH9oQipc"
}

En caso contrario, te arrojará uno de los siguientes errores:

CÓDIGOMENSAJEEJEMPLODESCRIPCIÓN
E004Error en solicitud de JWT{ code: “E004”, message: “Error en solicitud de JWT” }Si el comercio tiene una regla de 3D Secure activa y hubo un problema durante la inicialización del servicio, se regresará un error con código E004.
E018Longitud de tarjeta inválida{ code: “E018”, message: “Longitud de tarjeta inválida” }Por favor, verifica que la longitud de la tarjeta sea válida.
E019Comercio no tiene activo 3DS{ code: “E019”, message: “Comercio no tiene activo 3DS” }El comercio no tiene activo el servicio de 3DS. Para activarlo, revisa la guía herramientas de detección de fraude.

Paso 2. Solicita un token de tarjeta

Solicita un token de tarjeta enviando el JWT obtenido en el paso anterior.

{
"card": {
"name": "John Doe",
"number": "4000000000000002",
"expiryMonth": "01",
"expiryYear": "28",
"cvv": "123"
},
"totalAmount": 59,
"currency": "USD",
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTQ2NTg0ODgsImlhdCI6MTY1NDY1MTI4OCwiaXNzIjoiNWVhMzJmZDJmZjQ2NDU2OTY3YjUyNDliIiwianRpIjoiZjc4NzQzNTctMmY2Zi00OTExLTg3MDctZDBmN2RlYTZlNTk4IiwiT3JnVW5pdElkIjoiNWVhMzJmZDJhZDA3ZDIxYTM2OTc4OGFlIiwiUmVmZXJlbmNlSWQiOiIyZDdhOTA2OS04MjhjLTQxNDItYWYwNC1hMjZjNWI4YzQ3MjMifQ.5nmFrf3sOAxKNIcJTzc5i2GNY5ALABpu42YsrHIibio"
}

Si el comercio tiene reglas 3D Secure activas y se inicializó 3D Secure correctamente como se describió en el paso 1, además del token, se devolverán otras propiedades que serán requeridas en el siguiente paso.

Si una transacción requiere autenticación 3D Secure por parte del tarjetahabiente, se devolverá la propiedad authRequired dentro del objeto security como true (security.authRequired).

ParámetroTipoDescripción
authRequiredBooleanaEste campo te indica si se requiere o no challenge de 3DS.
acsURLURLHace referencia a la URL de la página del reto que el usuario debe pasar (Access Control System).
specificationVersionStringSe refiere a la versión de 3DS aplicable.
authenticationTransactionIdStringID de la transacción verificada desde las marcas.
paReqStringSignifica Payer Authentication Request. Es un campo codificado en base64 que contiene información de tu comercio y del tarjetahabiente y que se envía al emisor para la autenticación
Nota: en caso de estar haciendo pruebas en ambiente UAT, se debe enviar sandbox.

Ejemplos

Objeto de respuesta con autenticación 3D Secure requerida

{
"token": "g9m2XG100000uut73n085881SMOP3bP1",
"secureService": "3dsecure",
"secureId": "61efd064-b9df-4c0c-81fb-5b39a5d0cf9f",
"security": {
"acsURL": "https://merchantacsstag.cardinalcommerce.com/MerchantACSWeb/pareq.jsp?vaa=b&gold=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"authenticationTransactionId": "uvvZn0ND0ukTOJIfhfi0",
"authRequired": true,
"paReq": "eNpVUstuwjAQvPsrItRTD7HjhAjQYokWqQVUSksqKm5RYkiU5oFjE/j72iFAK/mws7Nr78wagkRwPl3zSAnO4I3XdbjnVhqPe+p43BZkOSUqC97ns12yS0mPwWryyQ8MjlzUaVkwxyY2BXyFSF8hoiQsJIMwOjzNlszzh9TxAXcQQc7FbMr6nksdAviCEBRhztlivXh8ScpaWitRxiqSpRXwWqYF4JZHEJWqkOLMfOIBvgIESvywRMpqhHHTNHam6iRLq3Bf1nZU5oANjwDfh1spE9Va8ymNWfy9pZvca4Lso4k38isg1XybJ3kYTMaATQWCOJScUUIp8cnAIu5IH1cP0eYRhLkZhj30hzbRsjqIoDIPTS6oPzTU34wWpITgRXRmA09zN4SAn6qy4LpG23uLtYb75M+vxuRIGjd9z3UpNS63uG1PtTXUJ07bn7Y+YdODux3ibt06+vcNfgHbNq5L",
"specificationVersion": "2.2.0"
}
}

Objeto de respuesta con autenticación 3D Secure no requerida

{
"token": "URkTD3100000aSfrJk085881gtsxGts6",
"secureService": "3dsecure",
"secureId": "9903cc36-6e9c-42b0-bb76-34c9c4dbaff5",
"security": {
"acsURL": "",
"authenticationTransactionId": "",
"authRequired": false,
"paReq": "",
"specificationVersion": "2.2.0"
}
}

Objeto de respuesta sin 3D Secure

{
"token": "3c1518cf6f844e248880aad6187cf8d7"
}

Obtén más información sobre solicitar un token de tajeta.

Paso 3. Autentica una transacción a través de 3D Secure

En caso de que la propiedad security.authRequired obtenida en el paso anterior venga con el valor de true, será necesario realizar una autenticación por medio de 3D Secure. Para realizar una autenticación 3D Secure, es requerido llamar el método requestValidate3DS en Kushki.js o Kushki.js Hosted Fields, enviando el objeto de la respuesta del paso anterior.

Kushki.js

var callback = function(response) {
if(!response.code){
console.log(response);
} else {
console.error('Error: ',response.error, 'Code: ', response.code, 'Message: ',response.message);
}
}
kushki.requestValidate3DS({
secureId: "5e44449e-869b-4fed-bbca-e1bfa5af53c3",
security: {
acsURL: "https://authentication.cardinalcommerce.com/ThreeDSecure/V1_0_2/PayerAuthentication?issuerId\u00d2aa20412b0063aca652facd9g\u0034transactionId\u003dQhcf3XOjdZmjve336Vee2gb5rof1",
authenticationTransactionId: "1d8cf7jg5Bfn8Nj73mn7",
paReq: "eNpVUtluwjAQfPdXoH5A7DghtGixxFUViRt6iDfXGGJCDpykQL++doDSvu3sjtYzs4ZlqKXsLaQotWQwknnOt7Km1q2HyeIx6EW7w2dn09NjFXnxxn1gMG3P5YHBl9S5ShPmOsShgG8QmRVahDwpGHBx6AzGzKdXoH5A7DghtGixxpVUtluwjAQfPdXoH5A7DghtGixs4ZlqKXsLaQot0u4KqLQKRlUugzC4gP+AYQlHrPwqLImhgfj0cnKvMwUhnfprkj0hiwnSPAxn1gMG3P5YHBl9S5ShPmOsShOqLqJ7x73Gx2vVbgC0DwZoXklFCKXFpo0bcpu83qWht0u4KqLQKRlUugzC4gP+AYQlHrpfUGenfxtGEOl1jIRN0c3hECesjSRhmNC+62Nh7vy7otNVxQmtdkm3Ew/Jrv1Kp0X4elF8Pb6p/n2KH/k0skaqcyeVHfdaulqgoP20X4elF8Pb6p/n2KH/k0sv8\u003d",
specificationVersion: "2.2.0",
authRequired: true
}, callback);

Si el valor de la variable authRequired es igual a true el modal para validación de 3DS será presentado y tu cliente entonces recibirá el valor a ingresar por correo electrónico o mensaje de texto.

Si el valor de la variable authRequired es igual a false no se presentará el modal para validación 3DS.

La respuesta que recibirás en la función callback será:

{
"code":"3DS000",
"message":"ok"
}

En caso de error, la respuesta de la función callback será algo como:

{
"message":"error-message",
"code":"error-code",
"error": "error-message"
}

La respuesta de la autenticación la obtendrás en el cargo. Si la autenticación se declina, recibirás un código K322 y alguno de los subcódigos especificados en la guía de Códigos de error.

Kushki.js Hosted Fields

El método requestValidate3DS() recibe como parámetro el objeto obtenido en la respuesta del paso anterior.

import { init, IKushki } from "@kushki/js-sdk";
import { CardTokenResponse, requestValidate3DS, TokenResponse } from "@kushki/js-sdk/Antifraud";
const on3DSValidation = async () => {
try {
const kushkiInstance = await init({
inTest: true,
publicCredentialId: merchantId
});
const cardTokenResponse: CardTokenResponse = {
secureId: "secure_id",
secureService: "secure_service",
security: {
acsURL: "https://kushki.com",
authenticationTransactionId: "transaction_id",
authRequired: true,
paReq: "jwt",
specificationVersion: "2.0.1"
},
token: "token"
};
const response: TokenResponse = await requestValidate3DS(kushkiInstance, cardTokenResponse);
console.log(response);
} catch (error: any) {
console.log(error)
}
};
PROPIEDADTIPOREQUERIDODESCRIPCIÓN
kushkiInstanceIKushkiObjeto con información del comercio y el ambiente de trabajo.
secureInitRequestSecureInitRequestObjeto obtenido al inicializar el servicio de 3D Secure con el método requestSecureInit().

Si la autenticación 3D Secure ha sido exitosa, se devolverá el mismo token del paso 2 con las validaciones correspondientes para seguir con el flujo de pago.

{
"token": "3c1518cf6f844e248880aad6187cf8d7"
}

En caso de error durante la autenticación, se devolverá alguno de los siguientes mensajes:

CÓDIGOMENSAJEEJEMPLODESCRIPCIÓN
E005Campos 3DS inválidos (Invalid 3DS fields){ code: “E005”, message: “Campos 3DS inválidos” }Si el comercio tiene habilitada una regla 3DS y hubo un error en la autenticación 3DS, se regresará el código de error E005. Intente nuevamente asegurándose de ingresar los datos correctamente para la validación de 3DS.
E006Error en solicitud de validación de token (Token validation request error){ code: “E006”, message: “Error en solicitud de validación de token” }Si el comercio tiene habilitada una regla 3DS y hubo un error en la autenticación 3DS, se regresará el código de error E005. Intente nuevamente asegurándose de ingresar los datos correctamente para la validación de 3DS.

Consulta más sobre el método requestValidate3DS().

Paso 4. Realiza un cargo único o un cargo recurrente

Continua con el flujo de pago generando un cargo único o un cargo recurrente con el token validado en el paso anterior.

{
"token": "f5c64f7ac8ea42d5a58dcdc74de973dc",
"amount": {
"subtotalIva": 0,
"subtotalIva0": 16.98,
"ice": 0,
"iva": 0,
"currency": "USD"
},
"metadata": {
"Referencia": "987654"
},
"contactDetails": {
"documentType": "CC",
"documentNumber": "1234567890",
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"phoneNumber": "+593912345678"
},
"orderDetails": {
"siteDomain": "example.com",
"shippingDetails": {
"name": "John Doe",
"phone": "+593912345678",
"address1": "Eloy Alfaro 139 y Catalina Aldaz",
"address2": "centro 123",
"city": "Quito",
"region": "Pichincha",
"country": "Ecuador"
},
"billingDetails": {
"name": "John Doe",
"phone": "+593912345678",
"address1": "Eloy Alfaro 139 y Catalina Aldaz",
"address2": "centro 123",
"city": "Quito",
"region": "Pichincha",
"country": "Ecuador"
}
},
"productDetails": {
"product": [
{
"id": "198952AB",
"title": "eBook Digital Services",
"price": 10000,
"sku": "10101042",
"quantity": 1
},
{
"id": "198953AB",
"title": "eBook Virtual Selling",
"price": 6980,
"sku": "004834GQ",
"quantity": 1
}
]
},
"fullResponse": "v2"
}

Prueba tu integración

Existen tarjetas de prueba que puedes utilizar en modo prueba para asegurarte que tu integración está lista. Úsalas con cualquier CVV, 1234 como código OTP y fecha de expiración futura.

  • Transacción aprobada con generación de modal 3DS:
    • 4456528080389860
    • 4456529267234200
    • 4456529165328302
    • 4456524869770255
    • 4456523340069956
  • Transacción aprobada sin generación de modal 3DS:
    • 4456540000000063
    • 4456543371713314
    • 4456541982068615
    • 4456541249811088