ID: 17 - Bank Transfer (COP)

Channel: 17

Provider: Cobre

Payment Methods: Bank Transfer

Available Currencies

NameCodeCountry
Colombian PesosCOPColombia

Available Payment Methods

APMfilter_byPayer experience
PSEpseRedirected straight to the selected bank's online banking
NequinequiPush notification sent to the payer's Nequi app
BancolombiabancolombiaRedirected to Bancolombia's payment page
Bre-B QRbreb_qrQR code displayed on our checkout, scanned from any bank or wallet app
Bre-B Keybreb_keyBre-B key (llave) displayed on our checkout, entered in the banking app

If filter_by is not sent, the payer is taken to Cobre's checkout, where all available methods (PSE, Nequi, Bancolombia and Bre-B) are offered.

Request example

curl --location 'https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php' \
--form 'public_key="{YOUR_PUBLIC_KEY}"' \
--form 'time="2026-08-04 16:33:11"' \
--form 'amount="50000"' \
--form 'currency="COP"' \
--form 'trans_id="1"' \
--form 'time_expired="120"' \
--form 'url_ok="https://bit.ly/3S5aOwc"' \
--form 'url_error="https://bit.ly/3S5aOwc"' \
--form 'channel="17"' \
--form 'signature="{YOUR_SIGNATURE}"' \
--form 'shopper_information="{
        \"Phone\": \"3123456789\",
        \"email\": \"[email protected]\",
        \"name_shopper\": \"Fulano\",
        \"Num_doc_identi\": \"112345678\",
        \"type_doc_identi\": \"ce\",
        \"last_name_Shopper\": \"Da Silva\",
        \"country\":\"COL\",
        \"country_code\":\"+57\"}"'
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array('public_key' => "{YOUR_PUBLIC_KEY}",'time' => '2026-08-04 16:33:11','amount' => '50000','currency' => 'COP','trans_id' => '1','time_expired' => '120','url_ok' => 'https://bit.ly/3S5aOwc','url_error' => 'https://bit.ly/3S5aOwc','channel' => '17','signature' => "{YOUR_SIGNATURE}",'shopper_information' => '{
        "Phone": "3123456789",
        "email": "[email protected]",
        "name_shopper": "Fulano",
        "Num_doc_identi": "112345678",
        "type_doc_identi": "ce",
        "last_name_Shopper": "Da Silva",
        "country":"COL",
        "country_code":"+57"}'),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
import requests

url = "https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php"

payload = {'public_key': "{YOUR_PUBLIC_KEY}",
'time': '2026-08-04 16:33:11',
'amount': '50000',
'currency': 'COP',
'trans_id': '1',
'time_expired': '120',
'url_ok': 'https://bit.ly/3S5aOwc',
'url_error': 'https://bit.ly/3S5aOwc',
'channel': '17',
'signature': "{YOUR_SIGNATURE}",
'shopper_information': '{
        "Phone": "3123456789",
        "email": "[email protected]",
        "name_shopper": "Fulano",
        "Num_doc_identi": "112345678",
        "type_doc_identi": "ce",
        "last_name_Shopper": "Da Silva",
        "country":"COL",
        "country_code":"+57"}'}
files=[

]
headers = {}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)
var request = require('request');
var options = {
  'method': 'POST',
  'url': 'https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php',
  'headers': {
  },
  formData: {
    'public_key': "{YOUR_PUBLIC_KEY}",
    'time': '2026-08-04 16:33:11',
    'amount': '50000',
    'currency': 'COP',
    'trans_id': '1',
    'time_expired': '120',
    'url_ok': 'https://bit.ly/3S5aOwc',
    'url_error': 'https://bit.ly/3S5aOwc',
    'channel': '17',
    'signature': "{YOUR_SIGNATURE}",
    'shopper_information': '{\n        "Phone": "3123456789", \n        "email": "[email protected]",  \n        "name_shopper": "Fulano", \n        "Num_doc_identi": "112345678", \n        "type_doc_identi": "ce", \n        "last_name_Shopper": "Da Silva",\n        "country":"COL",\n        "country_code":"+57"}'
  }
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});

Response

The response body is the checkout URL, in plain text. Redirect the payer to it:

https://uat-payments.alps.cl/justpay/check-out/?channel=cobre&tokenID=Xk3p9MzRb2Lm7VtM4wYcJ8sH1dGfvB2q&alps=1

The URL can only be opened while the operation is pending. Once the payment reaches a final state the link stops working, so generate a new operation for every payment attempt.

If you prefer to build your own payment screen instead of redirecting, see Direct Integration.

Mandatory Data

AttributeMandatoryData typeDescription
public_keyTrueString (255)Public key, unique value that identifies the commerce
timeTrueDatetimeRequest date time
channelTrueIntegerPayment Channel. Use 17
amountTrueDoubleThe amount of the transaction. COP is processed in whole pesos: send integers
currencyTrueString (3)Transaction currency code. Only COP is accepted on this channel
trans_idTrueString (255)Transaction id
time_expiredTrueString (255)Time in minutes to expire the token. Most methods on this channel use a fixed expiration set by the provider — see Expiration Times
url_okTrueString (255)URL where shopper will be redirected from the online banking if payment was successful (Must be Https)
url_errorTrueString (255)URL where shopper will be redirected from the online banking if payment was wrong.(Must be Https)
signatureTrueString (255)Signature hash256: Review signature calculation
shopper_informationTrueJSON StringJSON String Data: Review JSON index & format

Optional Data

AttributeMandatoryData typeDescription
filter_byFalseString (21)Payment method. Only one value is accepted. If omitted, all methods are shown on Cobre's checkout. Required when direct_integration is used
user_bank_codeFalseString (4)Bank code for PSE. Required when filter_by is pse. Ignored for every other method
direct_integrationFalseBooleanSet to 1 to receive the payment data as JSON instead of a checkout URL. See Direct Integration

shopper_information JSON format

📘

Field shopper_information must be send in string format (JSON encode).

'{
        "Phone": "3123456789",
        "email": "[email protected]",
        "name_shopper": "Fulano",
        "Num_doc_identi": "112345678",
        "type_doc_identi": "ce",
        "last_name_Shopper": "Da Silva",
        "country":"COL",
        "country_code":"+57"
}'

The shopper_information field is a column corresponding to a json with the next keys. All of them are mandatory on this channel: if any key is missing the request is rejected with SHOPPER_FIELD_REQUIRED.

ParameterMandatoryData TypeDescription
name_shopperTrueString (255)Shopper's name
last_name_ShopperTrueString (255)Shopper's last name
type_doc_identiTrueString (4)Identification document. See Identification documents
Num_doc_identiTrueString (20)Identification document number. Length depends on the document type
emailTrueString (255)Shopper's email. The domain must be a real, resolvable one
country_codeTrueString (4)Country's phone code. Must be +57
PhoneTrueString (10)Shopper's phone number. 9 or 10 digits
countryTrueString (3)Country ISO code. Must be COL
❗️

Test emails such as [email protected] or [email protected] are rejected when the domain has no DNS records. Use a real domain in your integration tests.

Identification documents

type_doc_identiDocument TypeAccepted number format
CCCitizenship ID Card5 to 12 digits
NITTax Identification NumberExactly 10 digits (dots and hyphens are allowed and ignored)
CEForeigner Identification Card6 to 12 digits
TIIdentity Card5 to 11 digits
PASPassport6 to 14 alphanumeric characters
PPTTemporary Protection Permit6 to 15 digits
NUIPUnique Personal Identification Number8 to 12 digits
IDCCustomer Identifier5 to 20 characters
RCNCivil Birth Registration6 to 14 characters
DIEForeign Identification Document6 to 14 characters

The value is case-insensitive: cc and CC are both accepted. A document type outside this list returns SHOPPER_INVALID_IDTYPE; a number that does not match the expected format returns SHOPPER_INVALID_ID.

Filters

Using the parameter filter_by you may select the APM the payer will use. Only one value is accepted. Sending two or more values — for example pse, nequi — returns INVALID_FILTER_BY.

CurrencyAPMfilter_byNotes
COPPSEpseuser_bank_code is required
COPNequinequiThe payer approves the charge from the Nequi app
COPBancolombiabancolombia
COPBre-B QRbreb_qrWe render the QR code; time_expired is honoured
COPBre-B Keybreb_keyWe display the Bre-B key; time_expired is honoured

If the filter_by parameter is not provided or left empty, the payer is sent to Cobre's checkout with all methods available: PSE, Nequi, Bancolombia and Bre-B. This is the recommended option when you want the payer to choose.

📘

Send filter_by in lowercase. Values are matched exactly as sent when the payment is created.

Payment flow by method

The value of filter_by determines what the payer sees after being redirected to the checkout URL.

filter_byWhat happens
(omitted)Cobre's checkout opens with every method available, including the bank selector for PSE
pseThe payer is sent directly to the online banking of the bank identified by user_bank_code
bancolombiaThe payer is sent directly to Bancolombia's payment page
nequiThe charge is pushed to the payer's Nequi app. Our checkout shows the instructions and waits for approval
breb_qrOur checkout shows a QR code to be scanned from any bank or wallet app that supports Bre-B
breb_keyOur checkout shows a Bre-B key. The payer transfers the exact amount to that key from their banking app

For nequi, breb_qr and breb_key the payer stays on our checkout until the payment is confirmed, and is then redirected to url_ok. If the payment is rejected, cancelled or expires, they are redirected to url_error.

❗️

With breb_key the payer must transfer the exact amount of the operation. Transfers for a different amount are not matched to the payment.

How to Specify a Bank for PSE Payments

When filter_by is pse the bank must be included in the request: the payer is redirected straight to that bank's platform, so there is no bank selection step.

Steps to Specify a Bank

  1. Find the Bank Code
    Check the list of available banking entities and find the corresponding code. For example: Davivienda: 1051
  2. Add the Field to Your Request
    Include the user_bank_code field in your request body.
curl --location 'https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php' \
--form 'public_key="{YOUR_PUBLIC_KEY}"' \
--form 'time="2026-08-04 16:33:11"' \
--form 'amount="50000"' \
--form 'currency="COP"' \
--form 'trans_id="1"' \
--form 'time_expired="120"' \
--form 'url_ok="https://bit.ly/3S5aOwc"' \
--form 'url_error="https://bit.ly/3S5aOwc"' \
--form 'channel="17"' \
--form 'signature="{YOUR_SIGNATURE}"' \
--form 'filter_by="pse"' \
--form 'user_bank_code="1051"' \
--form 'shopper_information="{
        \"Phone\": \"3123456789\",
        \"email\": \"[email protected]\",
        \"name_shopper\": \"Fulano\",
        \"Num_doc_identi\": \"112345678\",
        \"type_doc_identi\": \"ce\",
        \"last_name_Shopper\": \"Da Silva\",
        \"country\":\"COL\",
        \"country_code\":\"+57\"}"'

Available Payment Flows

With filter_by="pse" and a bank specified: direct redirect to the bank's platform.

Without filter_by: the payer selects their bank from all available options on the checkout.

Note: filter_by="pse" without user_bank_code returns INVALID_USER_BANK_CODE. If you don't know the payer's bank in advance, omit filter_by so the bank can be chosen during the payment process. user_bank_code is ignored when filter_by is any value other than pse.

Expiration Times

The provider enforces a fixed expiration for most methods on this channel. time_expired is only applied to Bre-B and to the checkout with all methods.

filter_byExpiration
pse10 minutes (fixed — time_expired is ignored)
bancolombia10 minutes (fixed — time_expired is ignored)
nequi15 minutes (fixed — time_expired is ignored)
breb_qrtime_expired, between 5 and 4320 minutes (3 days). Default 120
breb_keytime_expired, between 5 and 4320 minutes (3 days). Default 120
(omitted)time_expired. Default 120 minutes

Values below the minimum or above the maximum are adjusted to the closest accepted value. The expiration shown to the payer on our checkout is always the effective one.

Direct Integration

Send direct_integration=1 to receive the payment data as JSON and render the payment screen yourself. In this mode:

  • filter_by becomes mandatory and must contain exactly one of pse, nequi, bancolombia, breb_qr or breb_key.
  • user_bank_code is mandatory for pse and is validated against the list of accepted codes.
  • No checkout URL is returned: you are responsible for showing the payment instructions and for tracking the result through the payment notification.
curl --location 'https://uat-payments.alps.cl/justpay/check-out/SecurePayment.php' \
--form 'public_key="zyssglikvtltbd2se2hudwl50jjomil2uytp7tpvjtxyfdw469jagk8yvnex9jks"' \
--form 'time="2026-08-04 16:33:11"' \
--form 'amount="50000"' \
--form 'currency="COP"' \
--form 'trans_id="1"' \
--form 'time_expired="120"' \
--form 'url_ok="https://bit.ly/3S5aOwc"' \
--form 'url_error="https://bit.ly/3S5aOwc"' \
--form 'channel="17"' \
--form 'signature="89d4443aadbf4c4d560a270e951336109ae24dfeaeb19b0451cdbb5ca582208f"' \
--form 'direct_integration="1"' \
--form 'filter_by="breb_qr"' \
--form 'shopper_information="{
        \"Phone\": \"3123456789\",
        \"email\": \"[email protected]\",
        \"name_shopper\": \"Fulano\",
        \"Num_doc_identi\": \"112345678\",
        \"type_doc_identi\": \"ce\",
        \"last_name_Shopper\": \"Da Silva\",
        \"country\":\"COL\",
        \"country_code\":\"+57\"}"'
❗️

In UAT, breb_qr and breb_key return fixed sample values (https://test.example.com/qr/12345 and @TESTKEY123) and no charge is created with the provider. Use these responses to validate your integration contract only; end-to-end Bre-B tests must be run in Production.

PSE and Bancolombia response

{
  "payment_link": "https://payment.link/12345"
}

Redirect the payer to payment_link.

Bre-B QR response

{
  "operation_id": 123456,
  "qr_value": "0002010102...",
  "qr_code": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i..."
}
FieldDescription
operation_idOur internal identifier for the operation
qr_valuePayload to encode if you want to render the QR code with your own library
qr_codeReady-to-use QR image as a data URI, so you can display it without extra libraries

Bre-B Key response

{
  "operation_id": 123456,
  "key_value": "@LLAVEGENERADA"
}

Display key_value to the payer and instruct them to transfer the exact amount of the operation to that key from the Bre-B section of their banking app.

Nequi response

{
  "operation_id": 123456,
  "expired_at": "2026-08-04T18:48:11Z",
  "amount": "50000.00",
  "status": "pending",
  "steps": [
    {
      "step_number": 1,
      "title": "Desbloquea tu dispositivo",
      "description": "Asegúrate de tener conexión a internet y tu celular activo."
    },
    {
      "step_number": 2,
      "title": "Revisa la notificación Push",
      "description": "Busca la alerta emergente enviada por la app Nequi con el detalle del cobro."
    },
    {
      "step_number": 3,
      "title": "Accede al Centro de Notificaciones",
      "description": "Si no ves la alerta, abre tu App Nequi, inicia sesión y presiona el ícono de la campanita (🔔)."
    },
    {
      "step_number": 4,
      "title": "Autoriza la transacción",
      "description": "Selecciona la solicitud pendiente, verifica el monto y haz clic en Aceptar o Aprobar."
    },
    {
      "step_number": 5,
      "title": "Espera la confirmación",
      "description": "La pantalla se actualizará automáticamente cuando el pago sea procesado con éxito."
    }
  ]
}
FieldDescription
expired_atUTC timestamp after which the charge can no longer be approved
amountAmount of the operation
statusStatus reported by the provider when the charge was created
stepsInstructions, ready to display, describing how to approve the push notification

The push notification is sent as soon as the operation is created, so show these instructions immediately.

Recommendations

  • Send whole pesos. COP is processed without decimals. Fractional amounts are rounded before being sent to the provider.
  • Create one operation per payment attempt. The checkout URL is single-use and stops working once the operation reaches a final state.
  • Do not confirm orders on url_ok. The payer may return to your site before the provider confirms the payment. Wait for the notification.
  • Keep time_expired consistent with the method. For PSE, Nequi and Bancolombia the provider's fixed expiration applies regardless of the value you send.
  • Use lowercase in filter_by and send exactly one value.
  • Use real email domains in every environment, including tests.
  • Configure your rejection URL if you need to be notified of rejected, cancelled or expired payments; without it only successful payments are notified.

List of Banks and Financial Institutions in Colombia

Contains a list of the main banks and financial institutions that operate in Colombia, along with their respective identification codes. Use the code as the value of user_bank_code.

CodeEntity Name
1815Alianza fiduciaria
1558Ban
1059Bancamia s.a.
1040Banco agrario
1052Banco av villas
1013Banco bbva colombia s.a.
1032Banco caja social
1066Banco cooperativo coopcentral
1051Banco davivienda
1001Banco de bogota
1023Banco de occidente
1062Banco falabella
1063Banco finandina s.a. bic
1012Banco gnb sudameris
1006Banco itau
1071Banco j.p. morgan colombia s.a.
1047Banco mundo mujer s.a.
1060Banco pichincha s.a.
1002Banco popular
1065Banco santander colombia
1069Banco serfinanza
1303Banco union antes giros
1007Bancolombia
1061Bancoomeva s.a.
1283Cfa cooperativa financiera
1009Citibank
1370Coltefinanciera
1292Confiar cooperativa financiera
1289Cotrafa
1816Crezcamos
1097Dale
1551Daviplata
1637Iris
1286JFK cooperativa financiera
1070Lulo bank
1801Movii s.a.
1507Nequi
1809Nu. colombia compañia de financiamiento s.a.
1811Rappipay
1019Scotiabank colpatria
1804Ualá

The following codes are also accepted: 1053, 1067, 1121, 1802, 1803, 1805, 1808, 1812 and 1814.

A code outside this list returns INVALID_BANK_CODE when direct_integration is used. In the standard integration the code is forwarded to the provider, which rejects the operation if the entity is not available for PSE.

Errors

To better error handling, we'll return the errors in the response body using the following fields:

{
  "error":{
    "code":"INVALID_FILTER_BY",
    "message":"Invalid values in 'filter_by'. Allowed values: pse, nequi, bancolombia, breb_qr, breb_key"
  }
}

Error Codes

Request and authentication

CodeHTTPDescription
METHOD_NOT_ALLOWED405The request was not sent with POST
MISSING_CONTENT_TYPE400The Content-Type header is missing
UNSUPPORTED_CONTENT_TYPE415The Content-Type is not supported
EMPTY_JSON_BODY400A JSON request was sent with an empty body
INVALID_JSON400The JSON body could not be parsed
INVALID_JSON_STRUCTURE400The JSON body is not an object with key-value pairs
MISSING_FIELD400One or more mandatory fields are absent. The message lists them
EMPTY_FIELD400One or more mandatory fields were sent empty. The message lists them
INVALID_MERCHANT404No merchant matches the public_key
INVALID_SIGNATURE400The signature does not match the expected value
MERCHANT_DISABLED400The merchant account is not active. Contact [email protected]

Channel, currency and amount

CodeHTTPDescription
INVALID_CHANNEL400The channel is not enabled
DISABLED_CHANNEL400The channel is not available for your account
INVALID_CHANNEL_CURRENCY400The channel and currency combination is not enabled for your account
DISABLED_CURRENCY400The currency is not available for your account
INVALID_CURRENCY400The currency code is not a valid three-character ISO code
INVALID_CURRENCY_CHANNEL400The currency is not allowed on this channel. Channel 17 only accepts COP
INVALID_AMOUNT400amount is not a valid number
NEGATIVE_AMOUNT400amount must be greater than zero
MAX_AMOUNT_LIMIT400amount exceeds the maximum allowed for your account

Shopper information

CodeHTTPDescription
SHOPPERINFO_REQUIRED400shopper_information was not sent
SHOPPERINFO_BAD_FORMAT400shopper_information is not a JSON encoded string
SHOPPER_FIELD_REQUIRED400One or more keys of shopper_information are missing
SHOPPER_COUNTRY_NOTALLOWED400country must be COL
SHOPPER_INVALID_IDTYPE400type_doc_identi is not an accepted document type
SHOPPER_INVALID_ID400Num_doc_identi does not match the format of the document type
SHOPPER_INVALID_COUNTRY_CODE400country_code must be +57
SHOPPER_INVALID_PHONE400Phone must contain 9 or 10 digits
SHOPPER_INVALID_EMAIL_FORMAT400email is not valid or its domain cannot be resolved
BLACKLIST_DOCUMENT_ID400The document number is not allowed to transact

Payment method

CodeHTTPDescription
INVALID_FILTER_BY400filter_by contains an unsupported value, or more than one value
INVALID_USER_BANK_CODE400user_bank_code is required when filter_by is pse
FILTER_BY_REQUIRED400filter_by is mandatory when direct_integration is used
USERBANK_CODE_REQUIRED400user_bank_code is mandatory for pse when direct_integration is used
INVALID_BANK_CODE400user_bank_code is not in the list of accepted codes. The message lists them

Processing

CodeHTTPDescription
CREATION_ERROR400The payment could not be created with the provider. Retry with a new trans_id
📘

Provider codes are not returned in this response. When the provider rejects a payment after it has been created, its code and description are forwarded in the rejection_code and rejection_message fields of the rejection notification.