Reserve funds in subscriptions with Webpay OneClick

Register your customer's card details with Webpay OneClick to charge in two steps, in subscriptions

This functionality is available for the following models:

☐ Acquirer
☑ Aggregator

With this modality you will be able to register your customers’ card data through Transbank’s Webpay OneClick, to charge with the recurrence you define. In addition, you will be able to make the payment in two steps: authorization and capture.

Your customers will be able to use RedCompra credit cards to make recurring payments.

In addition, unlike other forms of integration, in this one the customer will be redirected to a Transbank payment portal and to their bank to complete the enrollment process.

How does it work?

A Webpay payment flow generally consists of the following steps:

diagrama-webpay

Integrating on-demand payments with Webpay OneClick consists of 2 stages: Enrollment and Charge. In this case, the charge stage is divided into two steps: Authorization and Capture.

To enroll the card:

  1. The user initiates the payment process on your site or app.
  2. The user is redirected to the Webpay portal to make the payment, where they enters their card data.
  3. Then, they go to the card issuer’s portal (the bank or other financial institution) where they authenticate using their credentials.
  4. Once the authentication is completed, the payment is authorized and the user returns to your site.
  5. A success or failure message is displayed depending on the result of the registration.

To make the charge, the steps are as follows:

  1. Obtain the token.
  2. Initiate the authorization with Kushki.
  3. Kushki will try to perform the authorization with the card issuer.
  4. If the response is positive, the merchant will be able to capture an amount and charge the customer’s card.

The flow you will integrate is as follows:

Webpay with Authorization and Capture

1. Enrollment

The first thing you must do to generate on-demand billing is to enroll your customer’s card. Here are the steps to do it:

Configure your front-end

The responsibility of the front-end is to collect the user’s card information in a secure way, tokenize it through Kushki’s servers and then send it to your back-end to initiate the card enrollment process so that you can then charge them.

You have two options to integrate: Kajita and Kushki.js.

Kajita

Kushki has payment forms ready to collect card information securely. You can use any of our versions:

  • Cajita: the first version of the payment form. It is not customizable.
  • Kajita: the second version. It allows you to customize your payment forms from your Administration Console and even have several versions of Kajita.

Create and customize your Kajitas

With Kushki you can create your Kajitas from the Administration Console. Click here to learn how to do it.

Configure Kajita

Include the kushki-checkout.js script in your checkout page by adding it to the <head> of your HTML file. Always load kushki-checkout directly from cdn.kushkipagos.com. Do not include the script in a bundle or package or host a copy of it.

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

Add Kajita to your site

Kajita needs a space within your page. Enter the following code in the <body> of your site where you want the payment form to be displayed.

For Kajita (v.2):

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

For Cajita (v.1):

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

Remember to configure the action of the action form according to the corresponding endpoint in your back-end, to get the token.

Then, add the script tag. Make sure the form has loaded.

For Kajita (v.2) you will be able to get the script from your Admin Console as explained here.

<script type="text/javascript">
var kushki = new KushkiCheckout({
kformId: "HmJXukKb5",
form: "my-form",
publicMerchantId: "${publicCfredentialId}",// Replace this with your public key
amount: {
subtotalIva: 0,
iva: 0,
subtotalIva0: 1000,
}
});
</script>

For v.1 (Cajita), add the following script, make sure the form has loaded and add the callback_url which corresponds to the address to which you will return your customer once he completes the process from Webpay Oneclick.

<script type="text/javascript">
var kushki = new KushkiCheckout({
form: "payment-form",
merchant_id: "88ba4bff110548d09acde8d326c71253", // Replace this with your Public Key
amount: "20000",
currency: "CLP",
payment_methods:["card_async"],
is_subscription: true,
inTestEnvironment: true, // Configured in test mode
callback_url: "https://my-ecommerce.com/return" // URL to which the user will return after completing the registration process
});
</script>

This will create a predefined form on your page to register a credit card.

Kushki.js

Use Kushki.js if you need more control over the look & feel of your card form.

Configure Kushki.js
Option 1 - CDN

Use the following script tag at the end of the <body> on your payment page.

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

Install the package from npm.

npm install --save @kushki/js

Then import it into your code using the following code.

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

Add the following code to your application

var kushki = new Kushki({
merchantId: '88ba4bff110548d09acde8d326c71253', // Replace this with your Public Key
inTestEnvironment: true, // Configured in test mode
});
Collect user information and send it to your back-end.

You can collect user information as you wish. In this case we only need the email, so you can provide it directly if you already have it, or display an email field for the user to enter it.

Once the email is obtained, request the token from Kushki to send it to your back-end as follows:

kushki.requestSubscriptionCardAsyncToken({
currency: 'CLP',
email: your_users_email,
callbackUrl: 'https://my-ecommerce.com/return' // URL to which the user will return after completing the registration process
}, (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);
}
});

Configure your back-end

The responsibility of the back-end is to receive the token obtained from your front-end and initiate the card enrollment process with Kushki.

When the user submits the form, your front-end transfers a token to an endpoint you have specified. With this token, you must make a call to our subscription endpoint to initiate the registration and redirect the user.

  • Javascript
var request = require("request");
var options = {
method: 'POST',
headers: [
'Private-Merchant-Id': '0c0b08cd92fc491fb37365170164f7e9', // Replace this with your Private Key
'Content-Type': 'application/json'
]
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card-async/init', // Test environment
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
});

As a response to the call, you will get the redirectUrl variable that you should use to redirect the user to the Webpay OneClick payment gateway. Here your customer will finish the registration process.

2. Capture the transaction

Once the registration is complete, the client will be returned with a GET call to the callbackUrl provided as a parameter in step 1. This call will be accompanied by a parameter called subscriptionId located in the path, which represents the unique identifier of the subscription.

For example, for callbackUrl = "http://www.example.com/return will return the client to GET http://www.example.com/return?subscriptionId=1591842658589000 where subscriptionId is equal to 1591842658589000.

If there was an error in the registration, the client will be returned to GET http://www.example.com/return?code=E1&message=Rechazo where code and message tell you that the card registration did not finish correctly.

According to the response you receive, show the user a success or failure screen to inform the customer if the subscription was created correctly or if there was an error.

The next thing to do from your backend is to make an authorization request and then make the charge.

3. Authorize the charge

With the subscriptionId of your card received in the previous step, you must make a call to our authorization endpoint to initiate the reservation of a given amount.

  • Python
  • Javascript
  • PHP
import requests
url = "https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/authorize"
payload = {
"amount": {
"ice": 0,
"iva": 0,
"subtotalIva": 0,
"subtotalIva0": 600,
"currency": "CLP"
},
"name": "John",
"lastName": "Doe",
"email": "user@example.com",
"fullResponse": "v2"
}
headers = {
"Content-Type": "application/json",
"Private-Merchant-Id": "",
"Accept": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
import axios from 'axios';
const options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/authorize',
headers: {
'Content-Type': 'application/json',
'Private-Merchant-Id': '',
Accept: 'application/json'
},
data: {
amount: {ice: 0, iva: 0, subtotalIva: 0, subtotalIva0: 600, currency: 'CLP'},
name: 'John',
lastName: 'Doe',
email: 'user@example.com',
fullResponse: 'v2'
}
};
try {
const { data } = await axios.request(options);
console.log(data);
} catch (error) {
console.error(error);
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/authorize",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => [
'ice' => 0,
'iva' => 0,
'subtotalIva' => 0,
'subtotalIva0' => 600,
'currency' => 'CLP'
],
'name' => 'John',
'lastName' => 'Doe',
'email' => 'user@example.com',
'fullResponse' => 'v2'
]),
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"Private-Merchant-Id: "
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}

Once the response is obtained, save the ticketNumber as this will be the identifier to perform the capture later.

3.1. Generate the capture (Optional)

Once you need to collect the funds from the card, you must make the call to our capture endpoint.

Capture the amount you define according to the authorized, using the subscriptionId of the card and the ticketNumber obtained in the authorization.

  • Python
  • Javascript
  • PHP
import requests
url = "https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/capture"
payload = {
"ticketNumber": "319228478889680319",
"amount": {
"currency": "CLP",
"subtotalIva": 0,
"iva": 0,
"subtotalIva0": 600,
"ice": 0
},
"fullResponse": "v2"
}
headers = {
"Content-Type": "application/json",
"Private-Merchant-Id": "",
"Accept": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
import axios from 'axios';
const options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/capture',
headers: {
'Content-Type': 'application/json',
'Private-Merchant-Id': '',
Accept: 'application/json'
},
data: {
ticketNumber: '319228478889680319',
amount: {currency: 'CLP', subtotalIva: 0, iva: 0, subtotalIva0: 600, ice: 0},
fullResponse: 'v2'
}
};
try {
const { data } = await axios.request(options);
console.log(data);
} catch (error) {
console.error(error);
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-uat.kushkipagos.com/subscriptions/v1/card/subscriptionId/capture",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ticketNumber' => '319228478889680319',
'amount' => [
'currency' => 'CLP',
'subtotalIva' => 0,
'iva' => 0,
'subtotalIva0' => 600,
'ice' => 0
],
'fullResponse' => 'v2'
]),
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"Private-Merchant-Id: "
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
  • Javascript
  • Python
  • PHP
var request = require("request");
var options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/subscriptions/v1/card/291929129192912', // Replace with your subscription id
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)
# Your logic here ...
$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();
// Your logic here ...

3.2. Reversals or Refunds (Optional)

Once an authorization has been made, a reversal of the set-aside cannot be made. If the reserved amount is not captured, it will be automatically released after 7 days.

On the other hand, you will be able to make a refund of a charge already made, through this endpoint, in the first 7 days. If more than 7 days have passed since the capture, you will have to request a refund, which we will perform through the Transbank portal, up to 90 days.

3.3. Cancel a subscription (Optional)

If you want to unsubscribe a card so that it is no longer possible to receive on-demand payments with it, you will have to use the unsubscribe endpoint from your 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);
// Your logic here ...
});
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"))
# Your logic here ...
$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();
// Your logic here ...

4. Test your integration

There are test cards you can use in the UAT environment to make sure your integration is ready. Use them with any future expiration date.

CardNumberCVVOutcome
VISA4051 8856 0044 6623123Generates approved transactions
AMEX3700 0000 0002 0321234Generates approved transactions
MASTERCARD5186 0595 5959 0568123Generates declined transactions
Redcompra4051 8842 3993 7763Generates approved transactions
Redcompra4511 3466 6003 7060Generates approved transactions
Redcompra5186 0085 4123 3829Generates declined transactions
Prepago VISA4051 8860 0005 6590123Generates approved transactions
Prepago MASTERCARD5186 1741 1062 9480123Generates declined transactions