Cómo migrar a la nueva versión de PSE
Checkout API cuenta actualmente con una nueva integración PSE, que permitirá a los compradores utilizar este medio de pago de una manera sencilla y simplificada.
Si ya cuentas con una integración PSE implementada en Checkout API, podrás realizar una actualización a esta nueva versión a partir de la inclusión de nuevos campos durante la creación del pago. Sigue los pasos a continuación para saber cómo hacerlo de manera correcta.
Agregar nuevos campos al formulario de pago
Client-Side
Para comenzar la migración, deberás agregar nuevos campos obligatorios al formulario de pago que ya habías añadido a tu proyecto. Estos nuevos campos serán relativos a la dirección y el teléfono del comprador, tal como se muestra en la tabla a continuación:
Campo | Descripción |
payer.address.zip_code | Código postal del comprador. |
payer.address.street_name | Nombre de la calle del domicilio del comprador. |
payer.address.street_number | Número del domicilio del comprador. |
payer.address.neighborhood | Barrio al que pertenece la dirección del comprador. |
payer.address.city | Ciudad del comprador. |
payer.phone.area_code | Código de área del teléfono del comprador. |
payer.phone.number | Número de teléfono del comprador. |
En el ejemplo a continuación, encontrarás una nueva estructura de código que incluye todos estos campos obligatorios y los elementos HTML
que necesitarás en los próximos pasos.
HTML
<form id="form-checkout" action="/process_payment" method="post">
<div>
<div>
<label for="zipCode">Zip Code</label>
<input id="form-checkout__zipCode" name="zipCode" type="text">
</div>
<div>
<label for="streetName">Street Name</label>
<input id="form-checkout__streetName" name="streetName" type="text">
</div>
<div>
<label for="streetNumber">Street Number</label>
<input id="form-checkout__streetNumber" name="streetNumber" type="text">
</div>
<div>
<label for="neighborhood">Neighborhood</label>
<input id="form-checkout__neighborhood" name="neighborhood" type="text">
</div>
<div>
<label for="city">Ciudad</label>
<input id="form-checkout__city" name="city" type="text">
</div>
<div>
<label for="federalUnit">Unidad Federal</label>
<input id="form-checkout__federalUnit" name="federalUnit" type="text">
</div>
<div>
<label for="phoneAreaCode">PhoneAreaCode</label>
<input id="form-checkout__phoneAreaCode" name="phoneAreaCode" type="text">
</div>
<div>
<label for="phoneNumber">PhoneNumber</label>
<input id="form-checkout__phoneNumber" name="phoneNumber" type="text">
</div>
<div>
<label for="email">E-mail</label>
<input id="form-checkout__email" name="email" type="text">
</div>
<div>
<label for="personType">Tipo de persona</label>
<select id="form-checkout__personType" name="personType" type="text">
<option value="natural">Natural</option>
<option value="juridica">Jurídica</option>
</select>
</div>
<div>
<label for="identificationType">Tipo de documento</label>
<select id="form-checkout__identificationType" name="identificationType" type="text"></select>
</div>
<div>
<label for="identificationNumber">Número del documento</label>
<input id="form-checkout__identificationNumber" name="identificationNumber" type="text">
</div>
</div>
<div>
<div>
<label for="banksList">Banco</label>
<div id="banksList"></div>
</div>
</div>
<div>
<div>
<input type="hidden" name="transactionAmount" id="transactionAmount" value="100">
<input type="hidden" name="description" id="description" value="Nome do Produto">
<br>
<button type="submit">Pagar</button>
</div>
</div>
</form>
Obtener tipos de documentos
Client-Side
En esta nueva integración con PSE, es necesario poder obtener y enviar exclusivamente los tipos de documento que se corresponden con el tipo de persona seleccionada durante la adición del formulario de pago. Se trata de un cambio con respecto a la antigua integración, en la que no era necesaria esta diferenciación.
Para obtener los tipos de documento de manera automática, utiliza la siguiente función:
javascript
document.getElementById('form-checkout__personType').addEventListener('change', e => {
const personTypesElement = document.getElementById('form-checkout__personType');
updateSelectOptions(personTypesElement.value);
});
function updateSelectOptions(selectedValue) {
const naturalDocTypes = [
new Option('C.C', 'CC'),
new Option('C.E.', 'CE'),
new Option('Pasaporte', 'PAS'),
new Option('Tarjeta de Extranjería', 'TE'),
new Option('Tarjeta de Identidad ', 'TI'),
new Option('Registro Civil', 'RC'),
new Option('Documento de Identificación', 'DI')
];
const juridicaDocTypes = [
new Option('NIT', 'NIT')
];
const idDocTypes = document.getElementById('form-checkout__identificationType');
if (selectedValue === 'natural') {
idDocTypes.options.length = 0;
naturalDocTypes.forEach(item => idDocTypes.options.add(item, undefined));
} else {
idDocTypes.options.length = 0;
juridicaDocTypes.forEach(item => idDocTypes.options.add(item, undefined));
}
}
Listar bancos
Client-Side
Al crear un pago con PSE, es necesario enviar el código del banco que será utilizado para hacer la transferencia. Para ello, deberás listar los bancos disponibles y ofrecer las opciones al pagador, para que elija el banco de su preferencia.
Para obtener el listado de bancos disponibles para PSE primero deberás, desde el backend, obtener los medios de pago enviando un GET con tu Access Token al endpoint /v1/payment_methods, o bien obtenerlos mediante nuestras SDKs y enviarlos al frontend.
En el siguiente ejemplo, puedes ver cómo enviar los medios de pago por medio de un endpoint de aplicación, /payment_methods
. Una vez que este endpoint es llamado desde el frontend, el listado de bancos disponibles para PSE es obtenido a través del campo financial_institutions
dentro del objeto con id=pse
.
json
[
{
"id": "pse",
"name": "PSE",
"payment_type_id": "bank_transfer",
"status": "active",
"secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pse.gif",
"thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pse.gif",
"deferred_capture": "does_not_apply",
"settings": [],
"additional_info_needed": [
"entity_type"
],
"min_allowed_amount": 1600,
"max_allowed_amount": 340000000,
"accreditation_time": 30,
"financial_institutions": [
{
"id": "1040",
"description": "Banco Agrario"
},
{
"id": "1507",
"description": "NEQUI"
},
{
"id": "1052",
"description": "Banco AV Villas"
},
{
"id": "1032",
"description": "Banco Caja Social"
}
],
"processing_modes": [
"aggregator"
]
}
]
Para mostrar la lista de bancos, crea un un elemento select
en javascript, y enriquécelo con los datos devueltos en el llamado a la API, como también muestra el ejemplo.
javascript
function setPse() {
fetch('/payment_methods')
.then(async function(response) {
const paymentMethods = await response.json();
const pse = paymentMethods.filter((method) => method.id === 'pse')[0];
const banksList = pse.financial_institutions;
const banksListElement = document.getElementById('banksList');
const selectElement = document.createElement('select');
selectElement.name = 'financialInstitution';
banksList.forEach(bank => {
const option = document.createElement('option');
option.value = bank.id;
option.textContent = bank.description;
selectElement.appendChild(option);
});
banksListElement.appendChild(selectElement);
}).catch(function(reason) {
console.error('Failed to get payment methods', reason);
});
}
Para que los elementos dinámicos creados en javascript se carguen cuando la página termine de renderizar, deberás añadir el siguiente código:
javascript
(function initCheckout() {
try {
const docTypeElement = document.getElementById('form-checkout__identificationType');
setPse();
updateSelectOptions('natural')
}catch(e) {
return console.error('Error getting identificationTypes: ', e);
}
})();
Enviar pago
Server-Side
Enviar un pago con la nueva implementación de PSE implica sólo algunos cambios.
Deberás enviar un POST con los parámetros requeridos al endpoint /v1/payments y ejecutar la solicitud, pero será necesario añadir los nuevos campos obligatorios (address
y phone
). Aquí debajo puedes ver un ejemplo completo como referencia, seguido de una descripción de cada campo a enviar:
<?php
use MercadoPago\Client\Payment\PaymentClient;
use MercadoPago\MercadoPagoConfig;
MercadoPagoConfig::setAccessToken("YOUR_ACCESS_TOKEN");
$client = new PaymentClient();
$payment = $client->create([
"transaction_amount" => 5000,
"description" => "Product description",
"payment_method_id" => "pse",
"additional_info" => [
"ip_address" => "127.0.0.1"
],
"transaction_details" => [
"financial_institution" => $_POST['financialInstitution']
],
"callback_url" => "http://www.your-site.com",
"email" => $_POST['email'],
"identification" => [
"type" => $_POST['identificationType'],
"number" => $_POST['identificationNumber']
],
"address" => [
"zip_code" => $_POST['zipCode'],
"street_name": $_POST['streetName'],
"street_number": $_POST['streetNumber'],
"neighborhood": $_POST['neighborhood'],
"city": $_POST['city'],
"federal_unit": $_POST['federalUnit']
],
"phone" => [
"area_code" => $_POST['phoneAreaCode'],
"number" => $_POST['phoneNumber']
],
"entity_type" => "individual";
]);
echo implode($payment);
?>
import { Payment, MercadoPagoConfig } from 'mercadopago';
const client = new MercadoPagoConfig({ accessToken: '<ACCESS_TOKEN>' });
const payment = new Payment(client);
payment.create({
body: {
transaction_amount: 5000,
description: 'Product description',
payment_method_id: 'pse',
payer: {
entity_type: 'individual',
email: req.body.email,
identification: {
type: req.body.identificationType,
number: req.body.identificationNumber
}
address: {
zip_code: req.body.zipCode,
street_name: req.body.streetName,
street_number: req.body.streetNumber,
neighborhood: req.body.neighborhood,
city: req.body.city,
Federal_unit: req.body.federalUnit
},
phone: {
area_code: req.body.phoneAreaCode,
number: req.body.phoneNumber
}
},
additional_info: {
ip_address: '127.0.0.1'
},
transaction_details: {
financial_institution: req.body.financialInstitution
},
callback_url: 'http://www.your-site.com'
}
}).then(function(response) {
res.status(response.status).json({
status: response.body.status,
status_detail: response.body.status_detail,
id: response.body.id,
});
})
.catch(function(error) {
res.status(error.status).send(error);
});
MercadoPagoConfig.setAccessToken("YOUR_ACCESS_TOKEN");
PaymentClient client = new PaymentClient();
IdentificationRequest identification =
IdentificationRequest.builder()
.type(request.getIdentificationType())
.number(request.getIdentificationNumber())
.build();
PaymentPayerAddressRequest address =
PaymentPayerAddressRequest.builder()
.zipCode(request.getZipCode())
.streetName(request.getStreetName())
.streetNumber(request.getStretNumber())
.neighborhood(request.getNeighborhood())
.city(request.getCity())
.federalUnit(request.getFederalUnit())
.build();
PaymentPayerPhoneRequest phone =
PaymentPayerPhoneRequest.builder()
.areaCode(request.getPhoneAreaCode())
.number(request.getPhoneNumber())
.build();
PaymentPayerRequest payer =
PaymentPayerRequest.builder()
.email(request.getEmail())
.entityType("individual")
.identification(identification)
.address(address)
.phone(phone)
.build();
PaymentAdditionalInfoRequest additionalInfo =
PaymentAdditionalInfoRequest.builder()
.ipAddress("127.0.0.1")
.build();
PaymentTransactionDetailsRequest transactionDetails = PaymentTransactionDetailsRequest.builder()
.financialInstitution(request.getFinancialInstitution())
.build();
PaymentCreateRequest paymentCreateRequest = PaymentCreateRequest.builder()
.transactionAmount(new BigDecimal(5000))
.description("Product description")
.paymentMethodId("pse")
.additionalInfo(additionalInfo)
.transactionDetails(transactionDetails)
.notificationUrl("https://your-site.com")
.payer(payer)
.build();
client.create(paymentCreateRequest);
require 'mercadopago'
sdk = Mercadopago::SDK.new('ACCESS_TOKEN')
payment_data = {
transaction_amount: 5000,
description: "Product description",
payment_method_id: "pse",
additional_info: {
ip_address: "127.0.0.1"
},
transaction_details: {
financial_institution: params[: financialInstitution]
},
callback_url: "https://your-site.com"
payer: {
email: params[:email],
entity_type: "individual",
identification: {
type: params[: identificationType],
number: params[: identificationNumber]
}
address: {
zip_code: params[: zipCode],
street_name: params[: streetName],
street_number: params[: streetNumber],
neighborhood: params[: neighborhood],
city: params[: city],
federal_unit: params[: federalUnit]
}
phone: {
area_code: params[: phoneAreaCode],
number: params[: phoneNumber]
}
}
}
payment_response = sdk.payment.create(payment_data)
payment = payment_response[: response]
using System;
using MercadoPago.Client.Common;
using MercadoPago.Client.Payment;
using MercadoPago.Config;
using MercadoPago.Resource.Payment;
MercadoPagoConfig.AccessToken = "ACCESS_TOKEN";
var client = new PaymentClient();
var identification = new IdentificationRequest() {
Type = request.IdentificationType,
Number = request.IdentificationNumber
};
var address = new PaymentPayerAddressRequest() {
ZipCode = request.ZipCode,
StreetName = request.StreetName,
StreetNumber = request.StreetNumber,
Neighborhood = request.Neighborhood,
City = request.City,
FederalUnit = request.FederalUnit
};
var phone = new PaymentPayerPhoneRequest() {
AreaCode = request.PhoneAreaCode,
Number = request.PhoneNumber
};
var payer = new PaymentPayerRequest() {
Email = request.Email,
EntityType = "individual",
Identification = identification,
Address = address,
Phone = phone
};
var additionalInfo = new PaymentAdditionalInfoRequest() {
IpAddress = "127.0.0.1"
};
var transactionDetails = new PaymentTransactionDetailsRequest() {
FinancialInstitution = request.FinancialInstitution
};
var paymentCreateRequest = new PaymentCreateRequest() {
TransactionAmount = 5000,
Description = "Product description",
PaymentMethodId = "pse",
AdditionalInfo = additionalInfo,
TransactionDetails = transactionDetails,
CallbackUrl = "https://your-site.com",
Payer = payer
};
var payment = await client.CreateAsync(paymentCreateRequest);
import mercadopago
sdk = mercadopago.SDK("ACCESS_TOKEN")
payment_data = {
"transaction_amount": 5000,
"description": "Product description",
"payment_method_id": "pse",
"additional_info": {
"ip_address": "127.0.0.1"
},
"transaction_details": {
"financial_institution": request.POST.get("financialInstitution")
},
"callback_url": "https://your-site.com"
"payer": {
"email": request.POST.get("email"),
"entity_type": "individual",
"identification": {
"type": request.POST.get("identificationType"),
"number": request.POST.get("identificationNumber")
}
"address": {
"zip_code": request.POST.get("zipCode"),
"street_name": request.POST.get("streetName"),
"street_number": request.POST.get("streetNumber"),
"neighborhood": request.POST.get("neighborhood"),
"city": request.POST.get("city"),
"federal_unit": request.POST.get("federalUnit")
},
"phone": {
"area_code": request.POST.get("phoneAreaCode"),
"number": request.POST.get("phoneNumber")
}
}
}
payment_response = sdk.payment().create(payment_data)
payment = payment_response["response"]
curl --location --request POST 'https://api.mercadopago.com/v1/payments' \
-H 'Authorization: Bearer ENV_ACCESS_TOKEN' \
-H 'X-Idempotency-Key: SOME_UNIQUE_VALUE' \
-H 'Content-Type: application/json' \
--d '{
"transaction_amount": 5000,
"description": "Product description",
"payment_method_id": "pse",
"payer": {
"email": "test_user_19549678@testuser.com",
"entity_type": "individual",
"identification": {
"type": "CC",
"number": "76262349"
},
"address": {
"zip_code": "111",
"street_name": "siempre viva",
"street_number": "111",
"neighborhood": "sarasa",
"city": "salto",
"federal_unit": "1"
},
"phone": {
"area_code": "011",
"number": "2134242412"
}
},
"additional_info": {
"ip_address": "127.0.0.1"
},
"transaction_details": {
"financial_institution": "1009"
},
"callback_url": "http://www.your-site.com"
}'
La tabla a continuación contiene los campos obligatorios y sus especificaciones:
Campo | Descripción | Valores posibles/validaciones | Llamado para obtener los valores |
transaction_amount | Monto del pago. | Debe ser mayor a 0. | - |
transaction_details.financial_institution | Banco informado en el POST para hacer la transferencia electrónica. Se debe mostrar al usuario el listado de bancos y permitirle seleccionar. El listado se actualiza, por lo que se recomienda consumir la información cada una hora. | No debe ser nulo ni vacío y debe corresponder a un banco existente. | https://api.mercadopago.com/v1/payment_methods/search?site_id=MCO&id=pse&public_key=YOUR_PUBLIC_KEY |
payer.entity_type | Tipo de personería, natural o jurídica. | individual o association | - |
payer.identification.type | Tipo de documento del comprador. | Valores aceptados: - RC (Registro Civil de Nacimiento) - TI (Tarjeta de Identidad) - CC (Cedula de Ciudadania) - TE (Tarjeta de Extranjeria) - CE (Cedula de Extranjeria) - PAS (Pasaporte) - NIT - DI (Documento de Identificación) | curl -X GET \ 'https://api.mercadopago.com/v1/identification_types' \ -H 'Authorization: Bearer YOUR_PUBLIC_KEY' |
payer.identification.number | Tipo y número de documento del comprador. | String Debe tener de 1 hasta 15 posiciones numéricas. Si el tipo es 'Pasaporte', aceptará valores alfanumericos | - |
payer.first_name | Nombre del comprador. | Debe tener de 1 hasta 32 posiciones. | - |
payer.last_name | Apellido del comprador. | Debe tener de 1 hasta 32 posiciones. | - |
payer.address.zip_code | Código postal del comprador. | Debe tener exactamente 5 posiciones. | - |
payer.address.street_name | Nombre de la calle del domicilio del comprador. | Debe tener de 1 hasta 18 posiciones. | - |
payer.address.street_number | Número del domicilio del comprador. | Debe tener de 1 hasta 5 posiciones. | - |
payer.address.neighborhood | Barrio al que pertenece la dirección del comprador. | Debe tener de 1 hasta 18 posiciones. | - |
payer.address.city | Ciudad del comprador. | Debe tener de 1 hasta 18 posiciones. | - |
payer.phone.area_code | Código de área del teléfono del comprador. | Debe tener 3 posiciones. | - |
payer.phone.number | Número de teléfono del comprador. | String Debe tener de 1 hasta 7 posiciones solo acepta caracteres numéricos. | - |
additional_info.ip_address | Dirección IP del comprador, donde se genera el pago. | - | - |
callback_url | Página donde se redirecciona al comprador por defecto luego de realizar el pago dentro de la interfaz del banco, cuando el comprador indica que desea regresar a la tienda. Puedes ver mensajes sugeridos para mostrar al comprador en el subtítulo Ejemplos de mensajes para callback URL. | No debe ser nulo o vacío y debe tener, como máximo, 512 caracteres. | - |
notification_url | URL usada para notificar la aplicación que la transferencia ha finalizado. | No debe ser nulo o vacío y debe tener, como máximo, 512 caracteres. | - |
La respuesta mostrará el status pendiente
hasta que el comprador realice el pago. Además, el parámetro external_resource_url
devolverá una URL a la que debes redirigir al comprador para que finalice el flujo de pago.
json
{
"id": 1312147735,
...,
"operation_type": "regular_payment",
"payment_method_id": "pse",
"payment_type_id": "bank_transfer",
"payment_method": {
"id": "pse",
"type": "bank_transfer"
},
"status": "pending",
"status_detail": "pending_waiting_transfer",
...
"description": "Título del producto",
...
"callback_url": "http://www.your-site.com",
"installments": 1,
"transaction_details": {
...
"total_paid_amount": 5000,
...
"external_resource_url": "https://www.mercadopago.com.co/sandbox/payments/1312147735/bank_transfer?caller_id=1148920820&hash=f41dd14f-b3a6-4ac4-9b78-5cfeb5a35e77",
...
"financial_institution": "1009",
...
"bank_transfer_id": 129229,
"transaction_id": "10022214"
},
}
Ejemplos de mensajes para callback URL
Una vez que el comprador realiza el pago en la plataforma del banco seleccionado, este es redirigido a una callback URL, en la que se le informa el estado de su transacción.
En la nueva versión, este es un campo obligatorio, por lo que necesitas poder ofrecer mensajes acorde a los diferentes estados de la transacción.
A continuación, te mostramos ejemplos de mensajes que puedes ofrecerle, de acuerdo a los tres estados posibles en los que puede encontrarse un pago.