Reserva fondos en recurrencias con Webpay OneClick

Registra los datos de tarjeta de tus clientes con Webpay OneClick para cobrar en dos pasos, en pagos calendarizados

Con esta modalidad podrás registrar los datos de tarjeta de tus clientes a través de Webpay OneClick de Transbank, para cobrar con la recurrencia que definas. Además, podrás hacer el cobro en dos pasos: autorización y captura.

Tus clientes podrán suscribir tarjetas de crédito y débito RedCompra para realizar sus pagos periódicos. Actualmente es la única forma de aceptar pagos recurrentes con tarjetas de débito en Chile.

Además, a diferencia de otras formas de integración, en esta el cliente será redirigido a un portal de pagos de Transbank y a su banco para completar el proceso de inscripción.

¿Cómo funciona?

Un flujo de pago en Webpay generalmente consiste en los siguientes pasos:

diagrama-webpay

Integrar pagos calendarizados con Webpay OneClick consiste en 2 etapas: Inscripción y cobro. En este caso, la etapa de cobro se divide en dos pasos: Autorización y captura.

Para inscribir la tarjeta:

  1. El usuario inicia el proceso de pago en tu sitio o app.
  2. Se redirige al usuario al portal de Webpay para realizar el pago, donde ingresa sus datos de tarjeta.
  3. Luego, pasa al portal del emisor de la tarjeta (el banco u otra entidad financiera) donde se autentica utilizando sus credenciales.
  4. Una vez resuelta la autenticación, se autoriza el pago y el usuario vuelve a tu sitio.
  5. Se despliega un mensaje de éxito o fracaso dependiendo del resultado de la inscripción.

Para realizar el cobro, los pasos son los siguientes: 1. Obtener el token. 2. Inicia la autorización con Kushki. 3. Kushki intentará realizar la autorización con la entidad emisora de la tarjeta. 4. Si la respuesta es positiva, el comercio podrá capturar un monto y hacer efectivo un cobro en la tarjeta del cliente.

El flujo que integrarás es el siguiente:

Flujo Webpay Oneclick on demand y calendarizados con Auth y Captura

1. Inscripción

Lo primero que debes hacer para generar cobros calendarizados es inscribir la tarjeta de tu cliente. Estos son los pasos para realizarlo:

Configura tu front-end

La responsabilidad del front-end es recoger la información de tarjeta del usuario de una manera segura, tokenizarla a través de los servidores de Kushki y luego enviarla a tu back-end para iniciar el proceso de inscripción de tarjeta para que luego puedas realizar cobros.

Tiens dos opciones para integrar: Kajita y Kushki.js.

Kajita

Kushki cuenta con formularios de pago listos para recopilar información de tarjeta de forma segura. Podrás usar cualquiera de nuestras versiones:

  • Cajita: la primera versión del formulario de pagos. No es personalizable.
  • Kajita: la segunda versión. Te permite personalizar tus formularios de pago desde tu Consola de administración e incluso tener varias versiones de Kajita.

Crea y personaliza tus Kajitas

Con Kushki puedes crear tus Kajitas desde la Consola de administración. Haz clic aquí para aprender cómo hacerlo.

Configura Kajita

Incluye el script de kushki-checkout.js en tu página de pago añadiéndolo al <head> de tu archivo HTML. Siempre carga kushki-checkout directamente desde cdn.kushkipagos.com. No incluyas el script en un bundle o paquete ni hostees una copia de él.

<head>
<title>Checkout</title>
<script src="https://cdn.kushkipagos.com/kushki-checkout.js"> </script>
</head>

Añade Kajita a tu sitio

Kajita necesita un espacio dentro de tu página. Ingresa el siguiente código en el <body> de tu sitio donde quieras que se despliegue el formulario de pago.

Para Kajita (v.2):

<form id="my-form" action="/confirm" method="post">
<input type="hidden" name="cart_id" value="123">
</form>

Para Cajita (v.1)

<form id="payment-form" action="/confirm" method="post">
<input type="hidden" name="cart_id" value="123">
</form>

Recuerda configurar la acción del formulario action de acuerdo con el endpoint correspondiente en tu back-end, para obtener el token.

Luego, agrega el tag script. Asegúrate de que el formulario se haya cargado.

Para la Kajita (v.2) Podrás obtener dicho script desde tu Consola de Administración según lo explicado aquí.

<script type="text/javascript">
var kushki = new KushkiCheckout({
kformId: "HmJXukKb5",
form: "my-form",
publicMerchantId: "${publicCfredentialId}",// Reemplaza esto por tu credencial pública
amount: {
subtotalIva: 0,
iva: 0,
subtotalIva0: 1000,
}
});
</script>

Para la v.1 (Cajita), añade el siguiente script, asegúrate de que el formulario se haya cargado y agrega el callback_url que corresponde a la dirección a la cual retornarás a tu cliente una vez complete el proceso desde Webpay Oneclick.

<script type="text/javascript">
var kushki = new KushkiCheckout({
form: "payment-form",
merchant_id: "88ba4bff110548d09acde8d326c71253", // Reemplaza esto por tu Public Key
amount: "20000",
currency: "CLP",
payment_methods:["card_async"],
is_subscription: true,
inTestEnvironment: true, // Configurado en modo prueba
callback_url: "https://my-ecommerce.com/return" // URL a la cual retornará el usuario completado el proceso de inscripción
});
</script>

Esto creará un formulario predefinido en tu página para inscribir una tarjeta de crédito.

Kushki.js

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

Configura Kushki.js
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

var kushki = new Kushki({
merchantId: '88ba4bff110548d09acde8d326c71253', // Reemplaza esto por tu Public Key
inTestEnvironment: true, // Configurado en modo prueba
});
Recoge la información del usuario y envíala a tu back-end

Puedes recoger la información del usuario como tú desees. En este caso solo necesitamos el email, por lo que puedes proveerlo de manera directa si ya tienes ese dato, o desplegar un campo de email para que el usuario lo ingrese.

Una vez obtenido el email, solicita el token a Kushki para enviarlo a tu back-end de la siguiente manera:

kushki.requestSubscriptionCardAsyncToken({
currency: 'CLP',
email: your_users_email,
callbackUrl: 'https://my-ecommerce.com/return' // URL a la cual retornará el usuario completado el proceso de inscripción
}, (response) => {
if(!response.code){
console.log(response.token);
// Submit your code to your back-end
} else {
console.error('Error: ',response.error, 'Code: ', response.code, 'Message: ',response.message);
}
});

Configura tu back-end

La responsabilidad del back-end es recibir el token obtenido desde tu front-end e iniciar el proceso de inscripción de tarjeta con Kushki.

Cuando el usuario envía el formulario, tu front-end transfiere un token a un endpoint que hayas especificado. Con este token, deberás realizar una llamada a nuestro endpoint de suscripciones para iniciar el registro y redirigir al usuario.

  • Javascript
var request = require("request");
var options = {
method: 'POST',
headers: [
'Private-Merchant-Id': '0c0b08cd92fc491fb37365170164f7e9', // Reemplaza esto por tu Private Key
'Content-Type': 'application/json'
]
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card-async/init', // Ambiente de prueba
headers: {'content-type': 'application/json'},
body: {
"token": "0d9118c7bc054aeeb47094509ce3fa01",
"processorTransactionType":"CAPTURE",
"amount": {
"subtotalIva": 0,
"subtotalIva0": 20000
"ice": 0,
"iva": 0,
"currency": "CLP"
},
"planName": "Premium",
"periodicity": "custom",
"contactDetails":
{
"firstName": "Juan",
"lastName": "Flores",
"email": "pruebas@kushki.com",
"phoneNumber": "+593984775632",
"documentType": "CC",
"documentNumber": "194541123"
},
"metadata": {
"contractID": "157AB"
},
"startDate": "2022-05-12"
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
// Redirect your user to redirectUrl
});

Como respuesta a la llamada, obtendrás la variable redirectUrl que deberás utilizar para redirigir al usuario al portal de pagos de Webpay OneClick. Aquí tu cliente finalizará el proceso de inscripción.

2. Captura la transacción

Una vez terminado el registro, se retornará el cliente con una llamada GET al callbackUrl proporcionado como parámetro en el paso 1. Esta llamada irá acompañada de un parámetro llamado subscriptionId ubicado en la ruta, que representa el identificador único de la suscripción.

Por ejemplo, para callbackUrl = "http://www.example.com/return se retornará el cliente a GET http://www.example.com/return?subscriptionId=1591842658589000 donde subscriptionId es igual a 1591842658589000.

Si hubo un error en el registro, se retornará el cliente a GET http://www.example.com/return?code=E1&message=Rechazo donde code y message te indican que la inscripción de la tarjeta no finalizó correctamente.

De acuerdo a la respuesta que recibas, muestra al usuario una pantalla de éxito o fracaso para informar al cliente si la suscripción se creó correctamente o si hubo un error.

Lo siguiente será realizar desde tu backend una petición de autorización para luego hacer una captura.

3. Autoriza el cobro

Con el subscriptionId de tu tarjeta recibido en el paso anterior, deberás realizar una llamada a nuestro endpoint de autorización para iniciar la reserva de un monto determinado.

  • Python
  • Javascript
  • PHP
import http.client
conn = http.client.HTTPSConnection("api-uat.kushkipagos.com")
payload = "{\"amount\":{\"ice\":0,\"iva\":0,\"subtotalIva\":0,\"subtotalIva0\":6000,\"currency\":\"MXN\"},\"name\":\"Juan\",\"lastName\":\"Perez\",\"email\":\"juanp@kushkipagos.com\",\"orderDetails\":{\"siteDomain\":\"tuebook.com\",\"shippingDetails\":{\"name\": \"Diego Osorio\",\"phone\":\"+593988734644\",\"address\":\"Calle 13 Avenida 39 40\",\"city\":\"Lima\",\"region\":\"Lima Metropolitana\",\"country\":\"Perú\",\"zipCode\":\"170402\"},\"billingDetails\":{\"name\":\"Diego Osorio\",\"phone\":\"+593988734644\",\"address\":\"Calle 13 Avenida 39 40\",\"city\": "Lima","region": "Lima Metropolitana ","country": "Perú","zipCode": \"170402\"}},\"fullResponse\":true}
headers = { 'content-type': "application/json" }
conn.request("POST", "/subscriptions/v1/card/1574693127852000/authorize", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
var request = require("request");
var options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/1574693127852000/authorize',
headers: {'content-type': 'application/json'},
body: {
amount: {ice: 0, iva: 0, subtotalIva: 0, subtotalIva0: 6000, currency: 'MXN'},
name: 'Juan',
lastName: 'Perez',
email: 'juanp@kushkipagos.com',
orderDetails: {siteDomain: 'tuebook.com',
shippingDetails: {name: 'Diego Osorio', phone: +593988734644, address: 'Calle 13 Avenida 39 40', city: 'Lima', region: 'Lima Metropolitana', country: 'Perú', zipCode: 170402},
billingDetails: {name: 'Diego Osorio', phone: +593988734644, address: 'Calle 13 Avenida 39 40', city: 'Lima', region: 'Lima Metropolitana', country: 'Perú', zipCode: 170402}
},
fullResponse: true
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$client = new http\Client;
$request = new http\Client\Request;
$body = new http\Message\Body;
$body->append('{"amount":{"ice":0,"iva":0,"subtotalIva":0,"subtotalIva0":6000,"currency":"MXN"},"name":"Juan","lastName":"Perez","email":"juanp@kushkipagos.com","orderDetails": {"siteDomain":"tuebook.com","shippingDetails":{"name":"Diego Osorio","phone":"+593988734644","address":"Calle 13 Avenida 39 40","city": "Lima","region":"Lima Metropolitana","country":"Perú","zipCode":"170402"},"billingDetails":{"name": "Diego Osorio","phone":"+593988734644","address":"Calle 13 Avenida 39 40","city": "Lima","region":"Lima Metropolitana","country":"Perú","zipCode": "170402"}},"fullResponse":true}');
$request->setRequestUrl('https://api-uat.kushkipagos.com/subscriptions/v1/card/1574693127852000/authorize');
$request->setRequestMethod('POST');
$request->setBody($body);
$request->setHeaders(array(
'content-type' => 'application/json'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();

Una vez obtenida la respuesta, guarda el ticketNumber ya que será este el identificador para realizar luego la captura.

3.1. Genera la captura (Opcional)

Una vez que se requiera recolectar los fondos de la tarjeta, se deberá realizar la llamada a nuestro endpoint de captura.

Captura el monto que definas de acuerdo al autorizado, utilizando el subscriptionId de la tarjeta y el ticketNumber obtenido en la autorización.

  • Python
  • Javascript
  • PHP
import http.client
conn = http.client.HTTPSConnection("api-uat.kushkipagos.com")
payload = "{\"ticketNumber\":\"319228478889680318\",\"amount\":{\"currency\":\"PEN\",\"subtotalIva\":0,\"iva\":0,\"subtotalIva0\":600,\"ice\":0},\"fullResponse\":true}"
headers = { 'content-type': "application/json" }
conn.request("POST", "/subscriptions/v1/card/123442221212/capture", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
var request = require("request");
var options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/123442221212/capture',
headers: {'content-type': 'application/json'},
body: {
ticketNumber: '319228478889680318',
amount: {currency: 'PEN', subtotalIva: 0, iva: 0, subtotalIva0: 600, ice: 0},
fullResponse: true
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$client = new http\Client;
$request = new http\Client\Request;
$body = new http\Message\Body;
$body->append('{"ticketNumber":"319228478889680318","amount":{"currency":"PEN","subtotalIva":0,"iva":0,"subtotalIva0":600,"ice":0},"fullResponse":true}');
$request->setRequestUrl('https://api-uat.kushkipagos.com/subscriptions/v1/card/123442221212/capture');
$request->setRequestMethod('POST');
$request->setBody($body);
$request->setHeaders(array(
'content-type' => 'application/json'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
  • Javascript
  • Python
  • PHP
var request = require("request");
var options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/291929129192912', // Reemplázalo con tu id de suscripción
headers: {'content-type': 'application/json'},
body: {
language: "es",
token: "1cfaze100000qQ4dtN016410Ow7ot8nd",
amount: {
subtotalIva: 0,
subtotalIva0: 50000,
ice: 0,
iva: 0,
currency: "CLP"
},
deferred: {
months: 6
},
metadata: {
customerId: "123"
},
contactDetails: {
documentType: "CC",
documentNumber: "1009283738",
email: "test@test.com",
firstName: "Diego",
lastName: "Cadena",
phoneNumber: "+593988734644"
},
orderDetails: {
siteDomain: "tuebook.com",
shippingDetails: {
name: "Diego Cadena",
phone: "+593988734644",
address: "Eloy Alfaro 139 y Catalina Aldaz",
city: "Santiago de Chile",
region: "Santiago",
country: "Chile",
zipCode: "170402"
},
billingDetails: {
name: "Diego Cadena",
phone: "+593988734644",
address: "Eloy Alfaro 139 y Catalina Aldaz",
city: "Santiago de Chile",
region: "Santiago",
country: "Chile",
zipCode: "170402"
}
},
productDetails: {
product: [
{
id: "198952AB",
title: "eBook Digital Services",
price: 6990000,
sku: "10101042",
quantity: 1
},
{
id: "198953AB",
title: "eBook Virtual Selling",
price: 9990000,
sku: "004834GQ",
quantity: 1
}
]
},
fullResponse: true
},
json: true
};
request(options, (error, response, body) => {
if (error) throw new Error(error);
console.log(body);
});
import requests
url = "https://api-uat.kushkipagos.com/subscriptions/v1/card/291929129192912"
payload = "{\"language\":\"es\",\"token\":\"1cfaze100000qQ4dtN016410Ow7ot8nd\",\"amount\":{\"subtotalIva\":0,\"subtotalIva0\":50000,\"ice\":0,\"iva\":0,\"currency\":\"CLP\"},\"deferred\":{\"months\":6},\"metadata\":{\"customerId\":\"123\"},\"contactDetails\":{\"documentType\":\"CC\",\"documentNumber\":\"1009283738\",\"email\":\"test@test.com\",\"firstName\":\"Diego\",\"lastName\":\"Cadena\",\"phoneNumber\":\"+593988734644\"},\"orderDetails\":{\"siteDomain\":\"tuebook.com\",\"shippingDetails\":{\"name\":\"Diego Cadena\",\"phone\":\"+593988734644\",\"address\":\"Eloy Alfaro 139 y Catalina Aldaz\",\"city\":\"Santiago de Chile\",\"region\":\"Santiago\",\"country\":\"Chile\",\"zipCode\":\"170402\"},\"billingDetails\":{\"name\":\"Diego Cadena\",\"phone\":\"+593988734644\",\"address\":\"Eloy Alfaro 139 y Catalina Aldaz\",\"city\":\"Santiago de Chile\",\"region\":\"Santiago\",\"country\":\"Chile\",\"zipCode\":\"170402\"}},\"productDetails\":{\"product\":[{\"id\":\"198952AB\",\"title\":\"eBook Digital Services\",\"price\":6990000,\"sku\":\"10101042\",\"quantity\":1},{\"id\":\"198953AB\",\"title\":\"eBook Virtual Selling\",\"price\":9990000,\"sku\":\"004834GQ\",\"quantity\":1}]}}"
headers = { 'content-type': "application/json" }
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
# Tu lógica acá ...
$client = new http\Client;
$request = new http\Client\Request;
$body = new http\Message\Body;
$body->append('{\"language\":\"es\",\"token\":\"1cfaze100000qQ4dtN016410Ow7ot8nd\",\"amount\":{\"subtotalIva\":0,\"subtotalIva0\":50000,\"ice\":0,\"iva\":0,\"currency\":\"CLP\"},\"deferred\":{\"months\":6},\"metadata\":{\"customerId\":\"123\"},\"contactDetails\":{\"documentType\":\"CC\",\"documentNumber\":\"1009283738\",\"email\":\"test@test.com\",\"firstName\":\"Diego\",\"lastName\":\"Cadena\",\"phoneNumber\":\"+593988734644\"},\"orderDetails\":{\"siteDomain\":\"tuebook.com\",\"shippingDetails\":{\"name\":\"Diego Cadena\",\"phone\":\"+593988734644\",\"address\":\"Eloy Alfaro 139 y Catalina Aldaz\",\"city\":\"Santiago de Chile\",\"region\":\"Santiago\",\"country\":\"Chile\",\"zipCode\":\"170402\"},\"billingDetails\":{\"name\":\"Diego Cadena\",\"phone\":\"+593988734644\",\"address\":\"Eloy Alfaro 139 y Catalina Aldaz\",\"city\":\"Santiago de Chile\",\"region\":\"Santiago\",\"country\":\"Chile\",\"zipCode\":\"170402\"}},\"productDetails\":{\"product\":[{\"id\":\"198952AB\",\"title\":\"eBook Digital Services\",\"price\":6990000,\"sku\":\"10101042\",\"quantity\":1},{\"id\":\"198953AB\",\"title\":\"eBook Virtual Selling\",\"price\":9990000,\"sku\":\"004834GQ\",\"quantity\":1}]}}');
$request->setRequestUrl('https://api-uat.kushkipagos.com/subscriptions/v1/card/291929129192912');
$request->setRequestMethod('POST');
$request->setBody($body);
$request->setHeaders(array(
'content-type' => 'application/json'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
// Tu lógica acá ...

3.2. Anulaciones o Refund (Opcional)

Una vez realizada una autorización, no se podrá realizar una reversión de la separación de fondos. Si el monto reservado no es capturado, será liberado de forma automática a los 7 días.

Por otro lado, podrás realizar un refund de una captura ya efectuada, a través de este endpoint, en los primeros 7 días. Si ya transcurrieron más de 7 días de la captura, deberás solicitarnos hacer el refund, el cual realizaremos a través del portal de Transbank, hasta los 90 días.

3.3. Cancela una inscripción (Opcional)

Si deseas dar de baja una tarjeta para que no sea posible recibir pagos bajo demanda con esta, tendrás que usar el endpoint de cancelación de suscripción desde tu backend.

  • Javascript
  • Python
  • PHP
const request = require("request");
request({
method: 'DELETE',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/213123123123',
headers: {'content-type': 'application/json'}
}, (error, response, body) => {
if (error) throw new Error(error);
console.log(body);
// Tu lógica acá ...
});
import http.client
conn = http.client.HTTPSConnection("api-uat.kushkipagos.com")
headers = { 'content-type': "application/json" }
conn.request("DELETE", "/subscriptions/v1/card/213123123123", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
# Tu lógica acá ...
$client = new http\Client;
$request = new http\Client\Request;
$request->setRequestUrl('https://api-uat.kushkipagos.com/subscriptions/v1/card/213123123123');
$request->setRequestMethod('DELETE');
$request->setHeaders(array(
'content-type' => 'application/json'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
// Tu lógica acá ...

4. Prueba tu integración

Existen tarjetas de prueba que puedes utilizar en el ambiente UAT para asegurarte de que tu integración está lista. Úsalas con cualquier fecha de expiración en el futuro.

Tipo de tarjetaNúmeroCVVResultado
VISA4051 8856 0044 6623123Genera transacciones aprobadas
AMEX3700 0000 0002 0321234Genera transacciones aprobadas
MASTERCARD5186 0595 5959 0568123Genera transacciones rechazadas
Redcompra4051 8842 3993 7763Genera transacciones aprobadas
Redcompra4511 3466 6003 7060Genera transacciones aprobadas
Redcompra5186 0085 4123 3829Genera transacciones rechazadas
Prepago VISA4051 8860 0005 6590123Genera transacciones aprobadas
Prepago MASTERCARD5186 1741 1062 9480123Genera transacciones rechazadas