Envía dinero a una tarjeta
Sending funds to cards involves processing payments to a debit or credit card. This can be done in two ways: Through a 100% API direct integration (only available for PCI-compliant merchants). By performing prior card tokenization using the Hosted Fields library. The flow you will integrate is as follows:
Direct Integration (100% API)
1. (Optional) Obtain a one-time or subscription payment token
Before requesting the transfer of funds, you can tokenize the recipient’s card. This can be done through the following services:
- 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.
Note: If your merchant not PCI Compliance, you must use Kushki JS Hosted Fields to obtain a token from the front-end without handling sensitive data.
2. Request the Transfer of Funds to a Card
To send funds to a card, you must provide the card and recipient details, the amount, and the clientTransactionId
, a unique identifier on your side. Check here for the full structure in our API reference.
Examples
- 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": "GMR","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": "GMR","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" => "GMR","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;}?>
If the request is successful, you will receive the following response:
{"responseCode": "00","responseText": "Approved and completed successfully","ticketNumber": "XXXXXXX","transactionReference": "XXXXXXXX","otherDetails": {}}
In case of an error, you will receive a response containing the code field and the details object, where you can check the reason for the rejection.
{"code": "E001","details": {"Origin": "PushFundsService","Message": "paymentType: must be a valid value."}}
3. Check the Transaction Status
You can verify the status of a transaction in two ways:
1. Check via the API Get Transaction Status
You only need to send the transactionReference
or clientTransactionId
. The response will include the following information:
{"amount": 13,"processor": {"code": "00","message": "Approved and completed successfully"},"ticketNumber": "951738256068368362","transactionReference": "763274a1-b47b-493f-934f-047801cc04a0","transactionStatus": "APPROVAL"}
2. Webhook Configuration You can set up a webhook to receive notifications for approved or declined transactions. Check here for the full webhook structure.
Integration via Kushki.js Hosted Fields
With Hosted Fields, you can securely collect card and cardholder information through fields hosted on Kushki’s infrastructure. It returns a payout token that allows you to continue with the payment flow from the back-end
With the implementation of this library, you can obtain two types of tokens:
- One-time payment token:: for making a single payment to a card
- Subscription token: can be reused for multiple payments to a credit or debit card. You will receive a
suscriptionId
instead of a token.
1. Import Kushki.js Hosted Fields into your application
Option 1 - CDN
Import the Kushki.js Hosted Fields library into your application via a <script>
tag within the <body>
tag. Once imported, you will be able to access the resources described later to create a card payout flow with Kushki..
You need to import both the kushki.min.js
library (which contains the code necessary to store your merchant credentials) and the card.min.js
library (which contains the functionality needed for the card payout flow).
<script src="https://cdn.kushkipagos.com/js/latest/kushki.min.js"></script><script src="https://cdn.kushkipagos.com/js/latest/card.min.js"></script>
Option 2 - NPM
Install the Kushki.js Hosted Fields library as an npm package inside your application with the following code:
npm install --save @kushki/js-sdk
Option 3 - YARN
yarn install @kushki/js-sdk
Create an instance of KushkiOptions
To use the Kushki.js Hosted Fields library, you first need to create an instance of KushkiOptions
which allows you to declare the merchant’s public key and select the environment (test or production) using the init()
method.
Add the following code to your application:
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);}}
Check the reference for more information about the KushkiOptions instance.
2. Initialize the Form on the Front-End
Follow the steps below to render server-side fields on your site. This way, your users will be able to send money to cards.
Step 1. Define containers for the server-side fields.
Before calling the initCardPayoutToken(), method, it is required to place the necessary elements to render each field server-side.
<!DOCTYPE html><html lang="en"><body><form><div id="cardHolderName_id"/><div id="cardNumber_id"/><div id="isSubscription_id"/></form></body></html>
Step 2. Create an instance of CardPayoutOptions with the transaction information
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"}}}
Render Server-Side Fields with the initCardPayoutToken Method
After creating an instance of kushkiOptions
, you need to call the initCardPayoutToken()
function to initialize an instance of 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);}}
Check the reference for the hosted fields library for more information on form initialization.
Styles
Follow the same methodology used in Estilos de Token de Tarjeta. he key difference is that these styles specifically apply to the fields required for this tokenization method. Also, note that the isSubscription field is a checkbox, so specific styles must be applied for this type of input. For more details, click here.
Events
Use the same approach as in Eventos de Token de Tarjeta. However, these events apply to the specific fields required for this tokenization method. For more details, clic here.
3. Request a Card Payout Token
To obtain a card payment token, call th requestCardPayoutToken
method on the previously initialized ICardPayouts
instance. This method will also validate whether the fields contain valid values; if not, it will throw an exception.
This method returns a CardPayoutTokenResponse, object, which you must send to your backend to proceed with the fund transfer.
- Option 1. Subscription Token If the
isSubscription
field is checked, the response will be of type CardPayoutSubscriptionTokenResponse and will include asubscriptionId
. - Option 2. One-Time Token: : Otherwise, it will return a CardPayoutUniqueTokenResponse with a one-time-use token.
4. Configure Your Backend
The backend is responsible for receiving the token (or subscription ID) obtained from your front-end and initiating the payment process with Kushki.
When the user submits the card and cardholder details through the form you’ve specified, your front-end will return a token or a suscriptionId. With this token, you will need to call our Push Funds endpoints to process the payment to the card.
One-Time Payment Token
If it is a one-time payment token, you should call the payouts/card/v1/pushFunds
. service. Make sure you include the token in the body, along with the amount and other necessary information.
- 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;
Subscription Token
If it is a subscription token, you should call the service /payouts/card/subscriptions/pushFunds/{subscriptionId}
. Make sure to include the subscriptionId
as a path parameter and in the body, provide the amount and other information as shown in the following example.
- 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;
Optional: Delete a Subscribed Card
This step allows you to remove a previously subscribed card by sending the subscriptionId. Once deleted, no further fund transfers can be made to that card. More information here.
Test Your Integration
There are test cards you can use in the UAT environment to ensure your integration is ready.
Visa
Valid Card
- Declines:
4957030420210470
- Approves:
4957030420210454
Invalid Card: 4104920120500001
Mastercard
Valid Card:
5102589999999913
Invalid Card:
5204750000000003
Simulate response scenarios using specific amounts
During testing, you can simulate different error scenarios by sending specific values in the totalAmount
field. This applies to both the Push Funds operation and Push Funds in subscriptions.
The following table shows the behavior by brand and amount:
Brand | Amount (totalAmount ) | Response | Code | Message | Note |
---|---|---|---|---|---|
VISA | 10 | DECLINE | 501 | Transaction declined. Please contact your card issuer. | |
MASTERCARD | 10 | DECLINE | 501 | Transaction declined. Please contact your card issuer. | |
VISA | 20 | DECLINE | 504 | The entered card has been reported. | |
MASTERCARD | 20 | DECLINE | 514 | The entered card number is not valid. | |
VISA | 30 | DECLINE | 541 | This card has been reported as lost. | |
MASTERCARD | 30 | DECLINE | 543 | This card has been reported as stolen. | |
VISA | 40 | ERROR | E027 | A timeout occurred when sending the request to the card network. | Timeout with declined transaction |
MASTERCARD | 40 | ERROR | E027 | A timeout occurred when sending the request to the card network. | Timeout with declined transaction |
VISA | 50 | ERROR | E027 | A timeout occurred when sending the request to the card network. | Timeout with approved transaction |
MASTERCARD | 50 | ERROR | E027 | A timeout occurred when sending the request to the card network. | Timeout with approved transaction |