Como migrar do SDK JS V1 para SDK JS V2 com Secure Fields
No Mercado Pago, lançamos o Secure Fields, um novo recurso de segurança para processar pagamentos com cartão que está disponível apenas na versão mais atual do JS SDK e possui vários benefícios como:
- Implementação mais simples
- Maior segurança para sua loja
- Facilidade para obter a certificação PCI SAQ A
Nesse artigo explicaremos as configurações necessárias para a migração da utilização de SDK de JavaScript na versão 1 para a utilização da SDK de JavaScript na Versão 2 com Secure Fields.
Abaixo mostramos as principais diferenças entre as etapas de migração.
- Alteramos a forma de instanciar o Mercado Pago;
- Não utilizaremos mais as funções de callback de cada método, mas sim o retorno deles para trabalhar com os dados;
- Os nomes de alguns métodos também sofreram algumas pequenas alterações e estas ficaram mais claras nos snippets comparativos.
Veja abaixo um comparativo dos diagramas.
Alterar a importação do script
O nome do arquivo JS no CDN foi alterado e será necessário modificar no HTML a importação do script.
- V1
html
<script
src="https://secure.mlstatic.com/sdk/javascript/v1/mercadopago.js"></script>
- V2
html
<script src="https://sdk.mercadopago.com/js/v2"></script>
Instanciar Mercado Pago
Como mencionado anteriormente, a instanciação do Mercado Pago também foi alterada.
- V1
javascript
window.Mercadopago.setPublishableKey("YOUR_PUBLIC_KEY");
- V2
javascript
const mp = new MercadoPago("YOUR_PUBLIC_KEY");
Criar campos PCI
Com o Secure Fields, mudou um pouco a forma de implementação dos campos de card number
, expiration date
e security code
. Com essa nova proposta bem mais segura, não é necessário criar tags inputs destes campos em seu HTML, agora deveremos criar apenas as divs
onde os inputs serão renderizados e deixar que o Mercado Pago envie iframes para os campos, como nos exemplos abaixo.
- A data de vencimento na V1
html
<div>
<input type="text" placeholder="MM" id="cardExpirationMonth" data-checkout="cardExpirationMonth">
<span class="date-separator">/</span>
<input type="text" placeholder="YY" id="cardExpirationYear" data-checkout="cardExpirationYear">
</div>
- Card number na V1
html
<input type="text" id="cardNumber" data-checkout="cardNumber" />
- Código de segurança na V1
html
<input id="securityCode" data-checkout="securityCode" type="text" />
Agora, apenas com as divs
e os IDs
correspondentes, ficará da seguinte maneira:
- A data de vencimento na V2
html
<div id="expirationDate"></div>
- Card number na V2
html
<div id="cardNumber"></div>
- Código de segurança na V2
html
<div id="securityCode"> </div>
E além das divs
, no caso do Secure Fields precisaremos informar aos MP onde ele deverá montar os inputs. Utilizando como exemplo as divs
indicadas acima, o script ficará assim:
javascript
const cardNumberElement = mp.fields.create('cardNumber', {
placeholder: "Número do cartão"
}).mount('cardNumber');
const expirationDateElement = mp.fields.create('expirationDate', {
placeholder: "MM/YY",
}).mount('expirationDate');
const securityCodeElement = mp.fields.create('securityCode', {
placeholder: "Código de segurança"
}).mount('securityCode');
Com isso, agora temos os nossos campos PCI seguros dentro do formulário. Para mais informações sobre como configurar os iframes, acesse nosso Github.
Obter tipos de documento
Agora o getIdentificationTypes
retorna uma promise e a forma de popular a tag select mudou.
No caso da SDK V1, a tag select era populada automaticamente no select com id=’docType’
, depois da chamada do getIdentificationTypes()
.
html
<body
<select id="docType" name="docType" data-checkout="docType" type="text"></select>
</body>
javascript
window.Mercadopago.getIdentificationTypes();
Na V2 a chamada do método retorna uma promise com lista de identificationTypes
e você deverá popular a tag select com o ID que você quiser, utilizando o exemplo anterior com o id=’docType’
, a implementação ficaria da seguinte maneira:
getIdentificationTypes
é uma retorna uma promise e a mesma deve ser executada logo após a renderização, uma opção é usar uma
IIFE,
como no exemplo abaixo.javascript
(async function getIdentificationTypes() {
try {
const identificationTypes = await mp.getIdentificationTypes();
const identificationTypeElement = document.getElementById('docType');
createSelectOptions(identificationTypeElement, identificationTypes);
} catch (e) {
return console.error('Error getting identificationTypes: ', e);
}
})();
function createSelectOptions(elem, options, labelsAndKeys = { label: "name", value: "id" }) {
const { label, value } = labelsAndKeys;
elem.options.length = 0;
const tempOptions = document.createDocumentFragment();
options.forEach(option => {
const optValue = option[value];
const optLabel = option[label];
const opt = document.createElement('option');
opt.value = optValue;
opt.textContent = optLabel;
tempOptions.appendChild(opt);
});
elem.appendChild(tempOptions);
}
Obter método de pagamento do cartão
Agora, o getPaymentMethod
é o getPaymentMethods
(no plural). Ainda na V1 esse método recebia dois parâmetros, um objeto contendo o bin
(6 primeiros dígitos do cartão ainda na V1) e uma função de callback que seria executada no retorno do método.
- V1
javascript
window.Mercadopago.getPaymentMethod({
"bin": bin
}, callbackFn);
javascript
document.getElementById('cardNumber').addEventListener('change', guessPaymentMethod);
- V2
javascript
cardNumberElement.on('binChange', guessPaymentMethod);
A função que será executada no evento de binChange
receberá por parâmetro um objeto contendo o bin
. Na V2 esse getPaymentMethods
é uma promise que recebe apenas um objeto contendo o bin
como parâmetro e retorna um objeto contendo um array dos payment methods quando a promise for resolvida.
javascript
async function getPaymentMethods(data) {
const { bin } = data
const { results } = await mp.getPaymentMethods({ bin });
// O id do payment estará em results[0].id
…
}
Obter banco emissor
Antes o getIssuers
recebia dois parâmetros, o paymentMethodId
e uma função de callback que era executada no retorno do método.
- V1
javascript
window.Mercadopago.getIssuers(
paymentMethodId, callBackFn
);
function callBackFn(status, response) {
if (status == 200) {
response.forEach( issuer => {
...
});
}
}
Na V2 esse método correspondente é uma promise que recebe um objeto contendo bin
e o paymentMethodId
como parâmetros, retornando os issuers quando a promise for resolvida.
- V2
javascript
async function getIssuers(paymentMethodId, bin) {
const issuears = await mp.getIssuers({paymentMethodId, bin });
...
};
Obter quantidade de parcelas
Antes o getInstallments
recebia dois parâmetros, um objeto contendo o payment_method_id
, o amount
e o issuer_id
, e o outro parâmetro era uma função de callback que era executada no retorno do método.
- V1
javascript
window.Mercadopago.getInstallments({
"payment_method_id": paymentMethodId,
"amount": parseFloat(transactionAmount),
"issuer_id": parseInt(issuerId)
}, callbackFn
);
function callBackFn(status, response) {
if (status == 200) {
response[0].payer_costs.forEach( payerCost => {
...
});
}
}
Na V2 esse método é uma promise e recebe um objeto como parâmetro contendo o amount
, o bin
e o paymentTypeId
onde o paymentTypeId
deve sempre receber o valor credit_card
.
- V2
javascript
async function getInstallments(paymentMethodId, bin) {
const installments = await mp.getInstallments({
amount: document.getElementById('transactionAmount').value,
bin,
paymentTypeId: 'credit_card'
});
...
};
Criar token do cartão
Finalmente, no submit do formulário, é gerado o token que é enviado ao backend e isso continua funcionando parcialmente do mesmo jeito, só algumas mudanças nas invocações e nos nomes dos métodos.
O método de criação do token também teve alteração no nome, na V1 era createToken
e na V2 é createCardToken
.
Na V1, o método createToken
recebia dois parâmetros, o formulário, e a função de callback que é executada ao fim da criação do token.
- V1
javascript
window.Mercadopago.createToken($form, setCardTokenAndPay);
Na V2, o método recebe um objeto contendo o cardholderName
, identificationType
e o identificationNumber
, e esse método retorna uma promise com o token.
- V2
javascript
async function createCardToken(){
const token = await mp.fields.createCardToken({
cardholderName,
identificationType,
identificationNumber,
});
...
}
Enviar o pagamento
Agora com o token em mãos, basta adicionar o token ao formulário e submetê-lo, como explicado na documentação de Integração via Métodos Core.
Exemplo de implementação:
javascript
doSubmit = false;
document.getElementById('paymentForm').addEventListener('submit', getCardToken);
async function getCardToken(event) {
event.preventDefault();
if (!doSubmit) {
let $form = document.getElementById('paymentForm');
const token = await mp.fields.createCardToken({
cardholderName: document.getElementById('cardholderName').value,
identificationType: document.getElementById('docType').value,
identificationNumber: document.getElementById('docNumber').value,
})
setCardTokenAndPay(token.id)
}
};
function setCardTokenAndPay(token) {
let form = document.getElementById('paymentForm');
let card = document.createElement('input');
card.setAttribute('name', 'token');
card.setAttribute('type', 'hidden');
card.setAttribute('value', token);
form.appendChild(card);
doSubmit = true;
form.submit();
};
Outras alternativas
Existem duas outras alternativas de implementações que não englobam os core methods, que foram os métodos tratados neste artigo, e ambas as alternativas são tão seguras quanto a utilização dos core methods. Veja abaixo quais são essas alternativas.
Cardform
A integração de pagamentos via cartão é feita via cardform. Neste modo de integração, o MercadoPago.js é responsável pelos fluxos necessários para obtenção das informações obrigatórias para a criação de um pagamento. Quando inicializado, uma busca é realizada para recolher os tipos de documentos disponíveis para o país em questão. Veja mais informações na documentação do Checkout API.
Checkout Bricks
O Checkout Bricks é um conjunto de módulos de interface do usuário que já vêm prontos para o front-end e são otimizados para uma melhor usabilidade e conversão. Cada Brick pode ser utilizado de forma independente ou em conjunto, formando a experiência de um checkout completo. Veja mais informações na documentação do Checkout Bricks.