Envía dinero a una tarjeta

Enviar fondos a tarjetas consiste en procesar pagos hacia una tarjeta de débito o crédito. Esto se puede realizar de dos maneras:

  1. Mediante una integración directa 100% API (solo disponible para comercios PCI compliance).
  2. Realizando una tokenización previa de la tarjeta a través de la librería Hosted Fields.

El flujo que integrarás es el siguiente:

card payout technical flow

Integración Directa (100% API)

1. (Opcional) Obtén un token de pago único o de suscripción

Antes de solicitar el envío de fondos, puedes tokenizar la tarjeta del destinatario. Esto se puede hacer a través de los siguientes servicios:

Nota: Si tu comercio no es PCI Compliance, debes usar Kushki JS Hosted Fields para obtener un token desde el front-end sin manejar datos sensibles.


2. Solicita el envío de fondos a una tarjeta

Para enviar fondos a una tarjeta, debes proporcionar los detalles de la tarjeta y el destinatario, el monto y el clientTransactionId, un identificador único de tu lado. Consulta aquí la estructura completa en nuestra referencia API.

Ejemplo

  • Javascript
  • Python
  • PHP
const axios = require("axios");
const options = {
method: 'POST',
url: 'https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds',
headers: {
'Private-Merchant-Id': 'YOUR_PRIVATE_MERCHANT_ID',
'Content-Type': 'application/json'
},
data: {
"card": {
"name": "John Doe",
"number": "5102589999999913"
},
"clientTransactionId": "1234567890",
"amount": {
"currency": "CLP",
"totalAmount": 0.25
},
"fullResponse": "v2",
"paymentType": "FD",
"metadata": {
"key1": "key1"
},
"recipient": {
"address": "Lima Callse S/N",
"city": "Chicago",
"country": "PER",
"zipCode": "63368"
}
}
};
axios.request(options)
.then(response => console.log(response.data))
.catch(error => console.error("Error:", error));
import requests
import json
url = "https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds"
payload = {
"card": {
"name": "John Doe",
"number": "5102589999999913"
},
"clientTransactionId": "1234567890",
"amount": {
"currency": "CLP",
"totalAmount": 0.25
},
"fullResponse": "v2",
"paymentType": "FD",
"metadata": {
"key1": "key1"
},
"recipient": {
"address": "Lima Callse S/N",
"city": "Chicago",
"country": "PER",
"zipCode": "63368"
}
}
headers = {
'Content-Type': 'application/json',
'Private-Merchant-Id': 'YOUR_PRIVATE_MERCHANT_ID' # Reemplaza con tu ID
}
response = requests.post(url, data=json.dumps(payload), headers=headers)
print(response.status_code)
print(response.json())
<?php
$url = "https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds";
$data = [
"card" => [
"name" => "John Doe",
"number" => "5102589999999913"
],
"clientTransactionId" => "1234567890",
"amount" => [
"currency" => "CLP",
"totalAmount" => 0.25
],
"fullResponse" => "v2",
"paymentType" => "FD",
"metadata" => [
"key1" => "key1"
],
"recipient" => [
"address" => "Lima Callse S/N",
"city" => "Chicago",
"country" => "PER",
"zipCode" => "63368"
]
];
$payload = json_encode($data);
$headers = [
"Private-Merchant-Id: YOUR_PRIVATE_MERCHANT_ID",
"Content-Type: application/json"
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200) {
echo "Success: " . $response;
} else {
echo "Error: HTTP Code " . $httpCode . " - " . $response;
}
?>

Si la solicitud es correcta, recibirás la siguiente respuesta:

{
"responseCode": "00",
"responseText": "Approved and completed successfully",
"ticketNumber": "XXXXXXX",
"transactionReference": "XXXXXXXX",
"otherDetails": {}
}

En caso de error, recibirás una respuesta con el campo code y el objeto details, donde podrás verificar la causa del rechazo:

{
"code": "E001",
"details": {
"Origin": "PushFundsService",
"Message": "paymentType: must be a valid value."
}
}

3. Consultar el estado de la transacción

Puedes verificar el estado de una transacción de dos formas:

1. Consulta a través del API Get Transaction Status Solo necesitas enviar el transactionReference o el clientTransactionId. La respuesta incluirá la siguiente información:

{
"amount": 13,
"processor": {
"code": "00",
"message": "Approved and completed successfully"
},
"ticketNumber": "951738256068368362",
"transactionReference": "763274a1-b47b-493f-934f-047801cc04a0",
"transactionStatus": "APPROVAL"
}

2. Configuración de un webhook Puedes configurar un webhook para recibir notificaciones de transacciones aprobadas o rechazadas. Consulta aquí la estructura completa de los webhooks.

Integración via Kushki.js Hosted Fields

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

Con la implementación de esta librería puedes obtener dos tipos de token:

  • Token de pago único: para realizar un único pago a una tarjeta
  • Token de suscripción: puede reutilizarse para varios pagos a una tarjeta crédito o débito. Obtendrás un suscriptionId en lugar de un token.

1. 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 dispersión a tarjetas con Kushki.

Es necesario importar tanto la biblioteca kushki.min.js (la cuál trae el código necesario para almacenar las credenciales de tu comercio) como la biblioteca card.min.js (módulo el cuál trae las funcionalidades necesarias para el flujo de dispersión con tarjeta).

<script src="https://cdn.kushkipagos.com/js/latest/kushki.min.js"></script>
<script src="https://cdn.kushkipagos.com/js/latest/card.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

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 , KushkiOptions} 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.

2. Inicializa el formulario en el front-end

Sigue los pasos a continuación para poder renderizar los campos de lado del servidor en tu sitio. De esta manera, tus usuarios podrán enviar dinero a tarjetas.

Paso 1. Definir los contenedores para los campos de lado del servidor.

Antes de llamar al método initCardPayoutToken(), es requerido colocar los elementos necesarios para poder renderizar cada campo de lado del servidor.

<!DOCTYPE html>
<html lang="en">
<body>
<form>
<div id="cardHolderName_id"/>
<div id="cardNumber_id"/>
<div id="isSubscription_id"/>
</form>
</body>
</html>

Paso 2. Crear una instancia de CardPayoutOptions con la información de la transacción

import { IKushki, init, KushkiError } from "@kushki/js-sdk";
import {
CardPayoutOptions,
ICardPayouts,
initCardPayoutToken
} from "@kushki/js-sdk/CardPayouts";
const kushkiOptions : KushkiOptions = {
publicCredentialId: 'public-merchant-id',
inTest: true
};
const options : CardPayoutOptions = {
fields: {
cardholderName: {
selector: "cardholderName_id"
},
cardNumber: {
selector: "cardNumber_id"
},
isSubscription: {
selector: "isSubscription_id"
}
}
}

Renderizar campos de lado del servidor con el método initCardPayoutToken

Después de crear una instancia de kushkiOptions, es necesario mandar a llamar a la función initCardPayoutToken() para inicializar una instancia de ICardPayouts.

const buildCardPayoutInstance = async () => {
try {
const kushkiInstance : Ikushki = await init(kushkiOptions);
const cardPayoutInstance: ICardPayouts = await initCardPayoutToken(kushkiInstance, options)
} catch (e: KushkiError) {
console.error(e.message);
}
}

Revisa la referencia de la librería hosted fields para más información sobre la inicialización del formulario .

Estilos

Sigue la misma metodología utilizada en Estilos de Token de Tarjeta. La diferencia clave es que estos estilos se aplican específicamente a los campos requeridos para este método de tokenización. Además, ten en cuenta que el campo isSubscription es de tipo checkbox, por lo que deben aplicarse estilos específicos para este tipo de entrada. Para más detalles, haz clic aquí.

Eventos

Utiliza el mismo enfoque que en Eventos de Token de Tarjeta. Sin embargo, estos eventos se aplican a los campos específicos requeridos para este método de tokenización. Para más detalles, haz clic aquí.

3. Solicita un token para Card payouts

Para obtener un token de pago con tarjeta, llama al método requestCardPayoutToken en la instancia de ICardPayouts previamente inicializada. Este método también valida si los campos contienen valores válidos; de lo contrario, generará una excepción.

Este método devuelve un objeto CardPayoutTokenResponse, que deberás enviar a tu backend para proceder con el envío de dinero.

4. Configura tu back-end

La responsabilidad del back-end es recibir el token (o el ID de suscripción) obtenido desde tu front-end e iniciar el proceso de pago con Kushki.

Cuando el usuario envía el número de tarjeta y del tarjetahabiente en el formulario que hayas especificado, tu front-end te devuelve un token o un suscriptionId. Con este token, deberás realizar una llamada a nuestros endpoints de Push Funds para realizar el envío de dinero a la tarjeta.

Token de pago único

En el caso de que sea un token de pago único, deberás consumir el servicio payouts/card/v1/pushFunds. Asegúrate de incluir el token en el body junto con el amount y demás información.

  • Javascript
  • Python
  • PHP
const fetch = require('node-fetch'); // Si usas Node.js, instala con: npm install node-fetch
const url = "https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds";
const headers = {
"Private-Merchant-Id": "your-private-merchat-id",
"Content-Type": "application/json"
};
const data = {
token: "74378g3yg4387437878387",
amount: {
currency: "PEN",
totalAmount: 19
},
clientTransactionId: crypto.randomUUID(), // Si usas Node.js 16+ o en navegador moderno
paymentType: "OG",
metadata: {
key1: "key1"
},
recipient: {
address: "Lima Callse S/N",
city: "Ambato",
zipCode: "123456"
},
fullResponse: "v2",
webhooks: [
{
events: ["approvedTransaction"],
urls: ["https://webhook.site/3aa8868d-43c8-4fc0-bcbf-a96f7e89a371"],
headers: [
{
label: "foo",
value: "bar"
}
]
}
]
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(data)
})
.then(response => response.json())
.then(responseData => console.log(responseData))
.catch(error => console.error("Error:", error));
import requests
import uuid
url = "https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds"
headers = {
"Private-Merchant-Id": "your-private-merchat-id",
"Content-Type": "application/json"
}
data = {
"token": "74378g3yg4387437878387",
"amount": {
"currency": "PEN",
"totalAmount": 19
},
"clientTransactionId": str(uuid.uuid4()),
"paymentType": "OG",
"metadata": {
"key1": "key1"
},
"recipient": {
"address": "Lima Callse S/N",
"city": "Ambato",
"zipCode": "123456"
},
"fullResponse": "v2",
"webhooks": [
{
"events": ["approvedTransaction"],
"urls": ["https://webhook.site/3aa8868d-43c8-4fc0-bcbf-a96f7e89a371"],
"headers": [
{
"label": "foo",
"value": "bar"
}
]
}
]
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
<?php
$url = "https://api-uat.kushkipagos.com/payouts/card/v1/pushFunds";
$headers = [
"Private-Merchant-Id: your-private-merchat-id",
"Content-Type: application/json"
];
$data = [
"token" => "74378g3yg4387437878387",
"amount" => [
"currency" => "PEN",
"totalAmount" => 19
],
"clientTransactionId" => uniqid(),
"paymentType" => "OG",
"metadata" => [
"key1" => "key1"
],
"recipient" => [
"address" => "Lima Callse S/N",
"city" => "Ambato",
"zipCode" => "123456"
],
"fullResponse" => "v2",
"webhooks" => [
[
"events" => ["approvedTransaction"],
"urls" => ["https://webhook.site/3aa8868d-43c8-4fc0-bcbf-a96f7e89a371"],
"headers" => [
[
"label" => "foo",
"value" => "bar"
]
]
]
]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;

Token de suscripción

En el caso de que sea un token de suscripción, deberás consumir el servicio /payouts/card/subscriptions/pushFunds/{subscriptionId}. Asegúrate de incluir el subscriptionId como path parameter y en el body el amount y demás información como en el siguiente ejemplo.

  • Javascript
  • Python
  • PHP
const fetch = require('node-fetch'); // Si usas Node.js, instala con: npm install node-fetch
const subscriptionId = "your-subscription-id"; // Reemplazar con el ID de la suscripción
const url = `https://api-uat.kushkipagos.com/payouts/card/subscriptions/pushFunds/${subscriptionId}`;
const headers = {
"Private-Merchant-Id": "your-private-merchat-id",
"Content-Type": "application/json"
};
const data = {
amount: {
currency: "PEN",
totalAmount: 0
},
clientTransactionId: crypto.randomUUID(), // Si usas Node.js 16+ o en navegador moderno
paymentType: "OG",
metadata: {
key1: "string"
},
recipient: {
address: "string",
city: "string",
zipCode: "string"
},
fullResponse: "v2",
webhooks: {
webhooks: [
{
events: ["approvedTransaction", "declinedTransaction"],
headers: [
{
label: "json",
value: "12"
}
],
urls: ["https://eof2hhkrta4ooo1.m.pipedream.net"]
}
]
}
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(data)
})
.then(response => response.json())
.then(responseData => console.log(responseData))
.catch(error => console.error("Error:", error));
import requests
import uuid
subscription_id = "your-subscription-id" # Reemplazar con el ID de la suscripción
url = f"https://api-uat.kushkipagos.com/payouts/card/subscriptions/pushFunds/{subscription_id}"
headers = {
"Private-Merchant-Id": "your-private-merchat-id",
"Content-Type": "application/json"
}
data = {
"amount": {
"currency": "PEN",
"totalAmount": 0
},
"clientTransactionId": str(uuid.uuid4()),
"paymentType": "OG",
"metadata": {
"key1": "string"
},
"recipient": {
"address": "string",
"city": "string",
"zipCode": "string"
},
"fullResponse": "v2",
"webhooks": {
"webhooks": [
{
"events": ["approvedTransaction", "declinedTransaction"],
"headers": [
{
"label": "json",
"value": "12"
}
],
"urls": ["https://eof2hhkrta4ooo1.m.pipedream.net"]
}
]
}
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
<?php
$subscriptionId = "your-subscription-id"; // Reemplazar con el ID de la suscripción
$url = "https://api-uat.kushkipagos.com/payouts/card/subscriptions/pushFunds/$subscriptionId";
$headers = [
"Private-Merchant-Id: your-private-merchat-id",
"Content-Type: application/json"
];
$data = [
"amount" => [
"currency" => "PEN",
"totalAmount" => 0
],
"clientTransactionId" => uniqid(),
"paymentType" => "OG",
"metadata" => [
"key1" => "string"
],
"recipient" => [
"address" => "string",
"city" => "string",
"zipCode" => "string"
],
"fullResponse" => "v2",
"webhooks" => [
"webhooks" => [
[
"events" => ["approvedTransaction", "declinedTransaction"],
"headers" => [
[
"label" => "json",
"value" => "12"
]
],
"urls" => ["https://eof2hhkrta4ooo1.m.pipedream.net"]
]
]
]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Opcional. Elimina una tarjeta suscrita.

Este paso permite eliminar una tarjeta previamente suscrita enviando el subscriptionId. Una vez eliminada, no se podrán realizar más envíos de fondos a dicha tarjeta. Más información aquí.

Prueba tu integración

Existen tarjetas de prueba que puedes utilizar en el ambiente UAT para asegurarte de que tu integración está lista.

Visa

Tarjeta Válida

  • Rechaza: 4957030420210470
  • Aprueba: 4957030420210454

Tarjeta Inválida: 4104920120500001

Mastercard

  • Tarjeta Válida:5102589999999913

  • Tarjeta Inválida:5204750000000003

Simula escenarios de respuesta con montos específicos

Durante tus pruebas, puedes simular distintos escenarios de error utilizando valores específicos en el campo totalAmount. Esto aplica tanto para la operación de Push Funds como para Push Funds en suscripciones.

A continuación se muestra el comportamiento por marca y monto:

MarcaMonto (totalAmount)RespuestaCódigoMensajeObservación
VISA10DECLINACIÓN501Transacción rechazada. Póngase en contacto con el emisor de su tarjeta
MASTERCARD10DECLINACIÓN501Transacción rechazada. Póngase en contacto con el emisor de su tarjeta
VISA20DECLINACIÓN504La tarjeta ingresada ha sido reportada.
MASTERCARD20DECLINACIÓN514El número de tarjeta ingresado no es válido
VISA30DECLINACIÓN541Esta tarjeta ha sido reportada como perdida
MASTERCARD30DECLINACIÓN543Esta tarjeta ha sido reportada como robada
VISA40ERRORE027Ocurrió un timeout al enviar la petición a la franquicia.Time out con transacción declinada
MASTERCARD40ERRORE027Ocurrió un timeout al enviar la petición a la franquicia.Time out con transacción declinada
VISA50ERRORE027Ocurrió un timeout al enviar la petición a la franquicia.Time out con transacción aprobada
MASTERCARD50ERRORE027Ocurrió un timeout al enviar la petición a la franquicia.Time out con transacción aprobada