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:
- Mediante una integración directa 100% API (solo disponible para comercios PCI compliance).
- 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:
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:
- Get Card Payout Token: Genera un token de pago único para una transacción.
- Get Subscription Token: Genera un
subscriptionId
, permitiendo enviar fondos múltiples veces a la tarjeta suscrita.
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 requestsimport jsonurl = "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 merchantinTest: 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.
- Opción 1. Token de suscripción: Si el campo
isSubscription
está marcado, la respuesta será del tipo CardPayoutSubscriptionTokenResponse e incluirá unsubscriptionId
. - Opción 2. Token de un solo uso: De lo contrario, retornará un CardPayoutUniqueTokenResponse con un token de un solo uso.
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-fetchconst 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 modernopaymentType: "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 requestsimport uuidurl = "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-fetchconst subscriptionId = "your-subscription-id"; // Reemplazar con el ID de la suscripciónconst 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 modernopaymentType: "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 requestsimport uuidsubscription_id = "your-subscription-id" # Reemplazar con el ID de la suscripciónurl = 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:
Marca | Monto (totalAmount ) | Respuesta | Código | Mensaje | Observación |
---|---|---|---|---|---|
VISA | 10 | DECLINACIÓN | 501 | Transacción rechazada. Póngase en contacto con el emisor de su tarjeta | |
MASTERCARD | 10 | DECLINACIÓN | 501 | Transacción rechazada. Póngase en contacto con el emisor de su tarjeta | |
VISA | 20 | DECLINACIÓN | 504 | La tarjeta ingresada ha sido reportada. | |
MASTERCARD | 20 | DECLINACIÓN | 514 | El número de tarjeta ingresado no es válido | |
VISA | 30 | DECLINACIÓN | 541 | Esta tarjeta ha sido reportada como perdida | |
MASTERCARD | 30 | DECLINACIÓN | 543 | Esta tarjeta ha sido reportada como robada | |
VISA | 40 | ERROR | E027 | Ocurrió un timeout al enviar la petición a la franquicia. | Time out con transacción declinada |
MASTERCARD | 40 | ERROR | E027 | Ocurrió un timeout al enviar la petición a la franquicia. | Time out con transacción declinada |
VISA | 50 | ERROR | E027 | Ocurrió un timeout al enviar la petición a la franquicia. | Time out con transacción aprobada |
MASTERCARD | 50 | ERROR | E027 | Ocurrió un timeout al enviar la petición a la franquicia. | Time out con transacción aprobada |