Dispersa con Bre-B

Disbursing payments with Bre-B means delivering funds in real time to your users using only the recipient’s payment key — without needing to know their bank account number. The key can be their national ID, phone number, email address, alphanumeric alias, or merchant code.

Ideal for:

  • Supplier or vendor payments
  • Marketplaces
  • Delivery applications
  • Gig economy platforms
  • Refunds and compensations

Operation details

The Bre-B disbursement process in Colombia follows this flow: Merchant → Kushki → Banco de la República (SPBVI) → Receiving Bank → Beneficiary.

ParameterDetail
Minimum amount per transaction1 COP
Maximum amount per transactionEquivalent to 1,000 UVT (Tax Value Units, updated annually by the DIAN). Each financial institution or user may set lower daily or per-transaction limits.
CurrencyCOP
Available banksAll Colombian banks (Banco de la República regulation)
API processing hours24/7
Settlement timeReal-time (maximum 30 seconds from initiation)
Response typeAsynchronous — the final result is delivered via webhook or by querying the Get Status endpoint

Important note: The Kushki API accepts and processes requests 24/7. Unlike ACH, Bre-B does not use banking cycles — processing is real-time through the SPBVI of the Banco de la República. You do not need to query the bank list before tokenizing.

Flow

The flow you will integrate is the following:

Flujo breb EN

Here you will learn how to integrate Bre-B money disbursements.

1. Tokenize the information

The first step is to obtain a token by sending the recipient’s key to Kushki. Unlike ACH, you do not need to query the bank list before this step — all Colombian banks support key-based transfers by Banco de la República regulation.

You must make the token request using our tokenization endpoint.

Required fields to obtain the token

Take into account the required fields in the token request body for Bre-B:

Disbursement with Bre-B key (accountType = KI, KP, KE, KA, KM)
- accountType
- accountNumber
- totalAmount
- currency

The fields documentType, documentNumber, bankId, and name are optional for Bre-B in Colombia.

Key types (accountType)

accountTypeKey type
KINational identification number
KPMobile phone number
KEEmail address
KAAlphanumeric alias
KMMerchant code

Valid formats for accountNumber

The accountNumber format is validated before sending any request to the payment network (fail-fast). An invalid format returns HTTP 400 immediately, without reaching the network.

accountTypeRequired format for accountNumber
KIUppercase alphanumeric characters. Minimum 1 character. No spaces or special characters.
KPExactly 10 digits. Must start with 3, followed by 9 digits.
KEValid email address. Maximum 30 characters before @ and 61 after. Must include a valid domain.
KAMust start with @. Uppercase alphanumeric characters only. No spaces or special characters.
KMExactly 10 digits. Must start with 00, followed by 8 digits.
  • Javascript
  • Python
  • PHP
var request = require('request');
// Example with mobile phone key (KP)
var options = {
'method': 'POST',
'url': 'https://api-uat.kushkipagos.com/payouts/transfer/v1/tokens', // Test environment
'headers': {
'Public-Merchant-Id': '', // Replace with your Public Key
'Content-Type': 'application/json'
},
body: JSON.stringify({
"accountType": "KP",
"accountNumber": "3001234567",
"totalAmount": 1000,
"currency": "COP"
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
var jsonData = JSON.parse(response.body);
console.log('Token:', jsonData.token);
// Show jsonData.keyResolution to the user to confirm the recipient
console.log('Recipient:', jsonData.keyResolution.ownerName);
});
import requests
import json
# Example with mobile phone key (KP)
url = "https://api-uat.kushkipagos.com/payouts/transfer/v1/tokens" # Test environment
payload = json.dumps({
"accountType": "KP",
"accountNumber": "3001234567",
"totalAmount": 1000,
"currency": "COP"
})
headers = {
'Public-Merchant-Id': '', # Replace with your Public Key
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
data = response.json()
print('Token:', data['token'])
# Show data['keyResolution'] to the user to confirm the recipient
print('Recipient:', data['keyResolution']['ownerName'])
$client = new http\Client;
$request = new http\Client\Request;
// Example with mobile phone key (KP)
$request->setRequestUrl('https://api-uat.kushkipagos.com/payouts/transfer/v1/tokens'); // Test environment
$request->setRequestMethod('POST');
$body = new http\Message\Body;
$body->append(json_encode([
"accountType" => "KP",
"accountNumber" => "3001234567",
"totalAmount" => 1000,
"currency" => "COP"
]));
$request->setBody($body);
$request->setOptions(array());
$request->setHeaders(array(
'Public-Merchant-Id' => '', // Replace with your Public Key
'Content-Type' => 'application/json'
));
$client->enqueue($request)->send();
$data = json_decode($client->getResponse()->getBody(), true);
echo 'Token: ' . $data['token'];
// Show $data['keyResolution'] to the user to confirm the recipient
echo 'Recipient: ' . $data['keyResolution']['ownerName'];

The response includes the token and the keyResolution object with the recipient’s data resolved by the payment network:

{
"token": "53de1cb6bbb54011a0a98053d48677e0",
"keyResolution": {
"keyValue": "3001234567",
"ownerName": "M**** G**** L****"
}
}
FieldDescription
tokenTransaction token. Expires in 30 minutes. Single-use, regardless of the transaction result.
keyResolution.keyValueExact value of the key, without any transformations.
keyResolution.ownerNameAccount holder name, returned masked by the payment network (e.g. M**** G**** L****).

2. Confirm the recipient

Once you have obtained the token and the keyResolution object, you must show the operator or end user the recipient’s information to confirm it is correct before initializing the transaction. This step is required by the Banco de la República.

Show the operator or user:

  • The key value: keyResolution.keyValue
  • The account holder name: keyResolution.ownerName (masked, e.g. M**** G**** L****)

3. Initialize the transaction

Once the recipient’s data has been confirmed, you must send the obtained token to start the disbursement process with Kushki. You must make a call to our initialization endpoint to start the payment. This step deducts the balance immediately from your disbursement account.

  • Javascript
  • Python
  • PHP
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api-uat.kushkipagos.com/payouts/transfer/v1/init', // Test environment
'headers': {
'Private-Merchant-Id': '', // Replace with your Private Key
'Content-Type': 'application/json'
},
body: JSON.stringify({
"token": "53de1cb6bbb54011a0a98053d48677e0", // Replace with the token you received
"amount": {
"subtotalIva": 0,
"subtotalIva0": 1000,
"iva": 0
},
"webhooks": [
{
"events": ["approvedTransaction", "declinedTransaction"],
"urls": ["https://your-endpoint.com/webhook"]
}
]
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
var jsonData = JSON.parse(response.body);
console.log('ticketNumber:', jsonData.ticketNumber);
console.log('status:', jsonData.status);
// Save the ticketNumber to query the status later
});
import requests
import json
url = "https://api-uat.kushkipagos.com/payouts/transfer/v1/init" # Test environment
payload = json.dumps({
"token": "53de1cb6bbb54011a0a98053d48677e0", # Replace with the token you received
"amount": {
"subtotalIva": 0,
"subtotalIva0": 1000,
"iva": 0
},
"webhooks": [
{
"events": ["approvedTransaction", "declinedTransaction"],
"urls": ["https://your-endpoint.com/webhook"]
}
]
})
headers = {
'Private-Merchant-Id': '', # Replace with your Private Key
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
data = response.json()
print('ticketNumber:', data['ticketNumber'])
print('status:', data['status'])
# Save the ticketNumber to query the status later
$client = new http\Client;
$request = new http\Client\Request;
$request->setRequestUrl('https://api-uat.kushkipagos.com/payouts/transfer/v1/init'); // Test environment
$request->setRequestMethod('POST');
$body = new http\Message\Body;
$body->append(json_encode([
"token" => "53de1cb6bbb54011a0a98053d48677e0", // Replace with the token you received
"amount" => [
"subtotalIva" => 0,
"subtotalIva0" => 1000,
"iva" => 0
],
"webhooks" => [
[
"events" => ["approvedTransaction", "declinedTransaction"],
"urls" => ["https://your-endpoint.com/webhook"]
]
]
]));
$request->setBody($body);
$request->setOptions(array());
$request->setHeaders(array(
'Private-Merchant-Id' => '', // Replace with your Private Key
'Content-Type' => 'application/json'
));
$client->enqueue($request)->send();
$data = json_decode($client->getResponse()->getBody(), true);
echo 'ticketNumber: ' . $data['ticketNumber'];
echo 'status: ' . $data['status'];
// Save the ticketNumber to query the status later

The response delivers a ticket number and the transaction status:

{
"status": "INITIALIZED",
"ticketNumber": "1234567890",
"transactionReference": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

4. Query the transaction status

Now that the disbursement is in process, you can check the transaction status using webhooks or by querying manually using our API.

Webhook

The transaction status is automatically notified at the moment the transfer is approved or declined. The payload includes the keyResolution object with keyValue and ownerName.

API

You can use our Get Status endpoint to manually query the status of a specific transaction.

  • Javascript
  • Python
  • PHP
var request = require('request');
var options = {
'method': 'GET',
'url': 'https://api-uat.kushkipagos.com/payouts/transfer/v1/transaction/{{ticketNumber}}', // Replace {{ticketNumber}}
'headers': {
'Private-Merchant-Id': '' // Replace with your Private Key
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
import requests
ticket_number = "1234567890" # Replace with the ticketNumber you received
url = f"https://api-uat.kushkipagos.com/payouts/transfer/v1/transaction/{ticket_number}"
headers = {
'Private-Merchant-Id': '' # Replace with your Private Key
}
response = requests.request("GET", url, headers=headers)
print(response.text.encode('utf8'))
$client = new http\Client;
$request = new http\Client\Request;
$ticketNumber = "1234567890"; // Replace with the ticketNumber you received
$request->setRequestUrl("https://api-uat.kushkipagos.com/payouts/transfer/v1/transaction/{$ticketNumber}");
$request->setRequestMethod('GET');
$request->setOptions(array());
$request->setHeaders(array(
'Private-Merchant-Id' => '' // Replace with your Private Key
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();

5. Test your integration

The Bre-B UAT environment runs on a payment network sandbox. Responses are simulated and replicate production behavior, but do not generate real money movements or network operations.

Successful key resolution

Use these values to obtain a token with a resolved keyResolution. All of them return an approved transaction.

accountTypeTest accountNumberSimulated keyResolution.ownerName
KP3001234567JUAN PEREZ
KEUSUARIO@CORREO.COMMARIA LOPEZ
KA@COLOMBIAANA MARTINEZ
KM0012345678COMERCIO PRINCIPAL SAS
KICC12345678LUIS GOMEZ

Tokenization errors (PT060)

Use these values to simulate an invalid or suspended key during the tokenization step. They return PT060 before the transaction is initiated.

accountTypeTest accountNumberSimulated scenario
KEBLOCKED@TEST.COMSuspended key
KM0011111111Key suspended by the participant
KP3000005001Error during key resolution
KIERRDICE9994Unexpected error during resolution

Payment scenario simulation by amount

To simulate error responses in payment processing, send the exact value indicated in the totalAmount field of the tokenization request. If the amount does not match any value in the table, the transaction will result in approved.

Synchronous errors — returned directly in the /init endpoint response, without waiting for the webhook:

totalAmountKushki responseCodeDescription
4001002An unexpected error occurred
4002068Invalid amount
5001073Transaction not permitted
5003074Bank or account not registered

Asynchronous errors — delivered via webhook or when querying Get Status, after /init returns INITIALIZED:

totalAmountKushki responseCodeDescription
6001076Error processing the payment
4016045Insufficient funds
4017077Pending response from other banks
4019077Pending response from other banks
4020041A system error occurred. Please try again
9999002An unexpected error occurred
4006080Invalid destination account
4007052Invalid account number
4010088Account does not exist
4011091Account with transaction block
4012071Invalid transfer amount
4013071Invalid transfer amount

6. Prepare your certification

Take the following guidelines into account to pass the technical certification (required to obtain production credentials):

  • Amount calculations are correct (subtotalIva, subtotalIva0, iva).
  • On-screen messages are shown in line with Kushki responses.
  • All Kushki responses are saved and logged (required in case support is needed).
  • The keyResolution object is shown to the operator or user and explicit confirmation is required before initializing the transaction.
  • The processor configured in the Console corresponds to Bre-B.
  • If a receipt does not need to be sent to the client’s email, the email should not be included in the token request.
  • If webhook notifications are received correctly, respond to the request with status 200.
  • The disbursement button is disabled after the first click to prevent double submission.
  • The Kushki logo must be visible to the client. You can find our logo in various formats here.
  • Ensure that the request body includes all required fields as specified in the API reference.

Accept webhooks

Handle post-disbursement events the right way.

Error codes

Check the error codes for Bre-B disbursements.