Nova integração do MPI Cielo para autenticação 3DS
Autenticação 3DS - novo MPI Cielo (V3)
A integração MPI V3 implementa o protocolo de autenticação EMV 3D Secure com arquitetura exclusivamente server-to-server. Nesse modelo, o estabelecimento controla todas as chamadas à API, incluindo a exibição do desafio ao portador quando necessário.
Versão do MPI vs versão do 3DSEsta documentação descreve o novo MPI Cielo (V3), que é o merchant plugin responsável pela integração da autenticação 3DS no modelo server-to-server.
É importante destacar que:
- A mudança de MPI V2 → MPI V3 refere-se apenas à evolução do plugin de integração (MPI).
- Não há alteração na versão do protocolo 3DS.
Ou seja:
Componente Versão MPI (integração) ✅ V3 (novo modelo server-to-server) 3DS (protocolo de autenticação) ✅ 2.2 (Visa, Mastercard) / 2.1 (Elo, Amex) ✅ Em resumo: você está adotando um novo modelo de integração (MPI V3), mas a autenticação 3DS continua seguindo as mesmas versões já suportadas anteriormente.
Nesta página
- Benefícios
- Pré-requisitos
- Ambientes, endpoints e token
- Fluxo de integração
- Etapa 1 – Preparar o front-end
- Etapa 2 – AUTH: obter o
access_token - Etapa 3 – INIT: inicializar a sessão
- Etapa 4 – Carregar e inicializar o script
- Etapa 5 – ENROLL: autenticar o cartão
- Etapa 6 – Exibir o desafio
- Etapa 7 – VALIDATE: validar a autenticação
- Códigos de retorno e erros
Benefícios
A integração MPI V3 oferece:
- Maior segurança: todas as chamadas sensíveis ficam no back-end;
- Controle total do fluxo de autenticação pelo estabelecimento;
- Flexibilidade para tratar cada cenário de autenticação de forma independente.
Pré-requisitos
Antes de iniciar a integração, você precisa ter o produto 3DS habilitado.
Ambientes, endpoints e tokens
APIs
| Operação | URL de sandbox | URL de produção |
|---|---|---|
access_token (AUTH) | https://mpisandbox.braspag.com.br/v3/auth/token | https://mpi.braspag.com.br/v3/auth/token |
| Inicialização (INIT) | https://mpisandbox.braspag.com.br/v3/3ds/init | https://mpi.braspag.com.br/v3/3ds/init |
| Matrícula e autenticação (ENROLL) | https://mpisandbox.braspag.com.br/v3/3ds/enroll | https://mpi.braspag.com.br/v3/3ds/enroll |
| Validação de autenticação (VALIDATE) | https://mpisandbox.braspag.com.br/v3/3ds/validate | https://mpi.braspag.com.br/v3/3ds/validate |
Scripts JavaScript
| Ambiente | mpi.js | mpiHelpers.js |
|---|---|---|
| Sandbox | https://mpisandbox.braspag.com.br/Scripts/V3/mpi.js | https://mpisandbox.braspag.com.br/Scripts/V3/mpiHelpers.js |
| Produção | https://mpi.braspag.com.br/Scripts/V3/mpi.js | https://mpi.braspag.com.br/Scripts/V3/mpiHelpers.js |
Sandbox: use para validar a integração antes de ir para produção. Para simular cenários de autenticação, utilize os cartões de teste 3DS.
Produção: use apenas para transações reais. Transações em produção geram custos e podem resultar em penalizações pelas bandeiras e pelos emissores.
Diferença entre tokens
O MPI utiliza dois tokens distintos:
- access_token:
- obtido na operação AUTH;
- é do tipo bearer;
- usado apenas no back-end;
- não deve ser exposto no front-end.
- token (INIT):
- retornado pela operação INIT;
- é um JWT;
- deve ser enviado ao front-end para inicializar o MPI.
Fluxo de integração
A integração segue uma sequência obrigatória de etapas distribuídas entre back-end e front-end:
[BACK-END] 1. AUTH → Obter `access_token`
[BACK-END] 2. INIT → Obter `referenceId` e `token`
[FRONT-END] 3. MPI.load → Carregar recursos e dependências
[FRONT-END] 4. MPI.init → Inicializar script com `token` e `referenceId`
[FRONT-END] 5. MPI.updateCard → Atualizar número do cartão
[FRONT-END] 6. Enviar pedido → Coletar dados do pedido e BrowserInfo
[BACK-END] 7. ENROLL → Autenticar cartão
│
├── Status 0 (Não autenticado) → Decisão da loja
├── Status 1 (Autenticado) → Prosseguir para autorização
└── Status 2 (Desafio) →
[FRONT-END] MPI.challenge → Exibir desafio ao portador
[FRONT-END] Enviar dados pós-desafio ao back-end
[BACK-END] 8. VALIDATE → Confirmar autenticação
├── Status 0 → Decisão da loja
└── Status 1 → Prosseguir para autorização
Importante: o
access_tokentem validade de 20 minutos em produção. A API bloqueia chamadas fora de ordem e chamadas repetidas. Respeite sempre a sequência: AUTH → INIT → ENROLL → VALIDATE. Não exponha oaccess_tokenno front-end.
Etapa 1 – Preparar o front-end
1.1 Incluir os scripts
Adicione as bibliotecas na página de checkout. Use as URLs correspondentes ao ambiente:
Sandbox:
<script src="https://mpisandbox.braspag.com.br/Scripts/V3/mpi.js"></script>
<script src="https://mpisandbox.braspag.com.br/Scripts/V3/mpiHelpers.js"></script>Produção:
<script src="https://mpi.braspag.com.br/Scripts/V3/mpi.js"></script>
<script src="https://mpi.braspag.com.br/Scripts/V3/mpiHelpers.js"></script>Código-fonte do mpi.js (sandbox)
O código abaixo é o conteúdo completo do mpi.js disponibilizado no ambiente de sandbox (https://mpisandbox.braspag.com.br/Scripts/V3/mpi.js). Ele é responsável pela, inicialização da sessão, atualização do cartão e exibição do desafio.
const MPI = (function () {
"use strict";
const DEFAULT_CONFIG = {
"Debug": true,
"Environment": "PRD"
};
const _logPrefixes = ["[MPI.V3]"];
const _lastError = {
"Number": null,
"Description": null,
"HasError": function () {
return this.Number !== null;
}
};
let _configuration = null;
let _referenceId = null;
let _loaded = false;
function loadConfiguration(config) {
if (config) {
_configuration = config;
return;
}
_configuration = DEFAULT_CONFIG;
log("Default configuration loaded", DEFAULT_CONFIG);
}
function _loadResources(config) {
loadConfiguration(config);
log("Debug =", getIsDebug());
log("Enviroment =", getEnvironment());
log("Config =", _configuration);
if (_loaded) {
log("Resources already loaded...");
return;
}
log("Loading resources...");
loadScript(getCardinalScriptUri(), function () {
_loaded = true;
log("Cardinal script loaded.");
notify("onLoadComplete");
});
}
function _initialize(token, referenceId) {
if (!_loaded) {
log("Resources not loaded...");
return;
}
_referenceId = referenceId;
log("Initializing...");
log("Telemetry Token =", token);
log("ReferenceId =", _referenceId);
Cardinal.configure({
timeout: "8000",
maxRequestRetries: "10",
logging: {
level: getCardinalLogLevel()
}
});
Cardinal.setup('init', {
jwt: token
});
Cardinal.on('payments.setupComplete', function (data) {
log("Setup complete.");
log("SetupCompleteData =", data);
notify("onReady");
});
Cardinal.on('payments.validated', function (data) {
log("[MPI]", "Payment validated.");
log("[MPI]", "ActionCode =", data.ActionCode);
log("[MPI]", "Data =", data);
switch (data.ActionCode) {
case 'SUCCESS':
case 'NOACTION':
case 'FAILURE':
notify("onValidationRequired", {
"TransactionId": data.Payment.ProcessorTransactionId
});
break;
case 'ERROR':
_lastError.Number = data.ErrorNumber;
_lastError.Description = data.ErrorDescription;
if (data.Payment && data.Payment.ProcessorTransactionId) {
notify("onValidationRequired", {
"TransactionId": data.Payment.ProcessorTransactionId
});
} else {
notify("onError", {
"Xid": null,
"Eci": null,
"ReturnCode": _lastError.HasError() ? _lastError.Number : "MPI901",
"ReturnMessage": _lastError.HasError() ? _lastError.Description : "Unexpected error",
"ReferenceId": null
});
}
break;
default:
_lastError.Number = data.ErrorNumber;
_lastError.Description = data.ErrorDescription;
if (data.ErrorDescription === "Success" &&
data.Payment &&
data.Payment.ProcessorTransactionId) {
notify("onValidationRequired", {
"TransactionId": data.Payment.ProcessorTransactionId
});
} else {
notify("onError", {
"Xid": null,
"Eci": null,
"ReturnCode": _lastError.HasError() ? _lastError.Number : "MPI902",
"ReturnMessage": _lastError.HasError() ? _lastError.Description : "Unexpected authentication response",
"ReferenceId": null
});
}
}
});
}
function canReadCardNumber() {
return typeof _configuration["cardNumberReader"] === "function";
}
function readCardNumber() {
if (canReadCardNumber()) {
return _configuration.cardNumberReader();
}
return "";
}
function _updateCard() {
let cardNumber = readCardNumber();
if (typeof cardNumber !== "string" || cardNumber.trim().length === 0) {
log("Card number is empty. Skipping update.");
return;
}
log("Updating card... ");
Cardinal.trigger("accountNumber.update", cardNumber);
}
function _challenge(challengeData, order) {
log("Showing challenge...");
log("Challenge object =", challengeData);
log("Order object =", order);
Cardinal.continue("cca", challengeData, order);
}
function getEnvironment() {
return _configuration.Environment || "PRD";
}
function getCardinalScriptUri() {
const environment = getEnvironment();
const enviroments = {
"TST": "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js",
"SDB": "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js",
"PRD": "https://songbird.cardinalcommerce.com/edge/v1/songbird.js"
};
return enviroments[environment];
}
function loadScript(url, callback) {
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = callback;
head.appendChild(script);
}
function getIsDebug() {
if (_configuration.Debug !== "undefined") {
return _configuration.Debug;
}
return false;
}
function log(...args) {
if (getIsDebug())
console.log(..._logPrefixes, ...args);
}
function getCardinalLogLevel() {
return getIsDebug() ? "verbose" : "off";
}
function isSubscribed(eventType) {
return typeof _configuration[eventType] === "function";
}
function notify(eventType, eventData) {
log("Notifying...");
log("Event type =", eventType);
log("Event data =", eventData || "None");
if (isSubscribed(eventType)) {
_configuration[eventType](eventData);
} else {
log("Not subscribed");
}
}
return {
load: function (config) {
_loadResources(config);
},
init: function (referenceId, initToken) {
_initialize(initToken, referenceId);
},
updateCard: function () {
_updateCard();
},
challenge: function (challengeData, order) {
_challenge(challengeData, order);
}
};
})();Pontos de atenção no
mpi.js:
MPI.load(config)carrega o Cardinal Commerce de forma assíncrona e acionaonLoadCompleteao concluir.MPI.init(referenceId, token)— a ordem dos parâmetros é(referenceId, token). Internamente, o método inverte a chamada para_initialize(token, referenceId).MPI.updateCard()lê o número do cartão viacardNumberReadere disparaCardinal.trigger("accountNumber.update", cardNumber). Caso o cartão seja atualizado durante a sessão ativa, é necessário chamarMPI.updateCard()novamente antes de seguir para o ENROLL.MPI.challenge(challengeData, order)chamaCardinal.continue("cca", challengeData, order)para exibir o desafio.- O callback
onValidationRequiredé acionado nosActionCode:SUCCESS,NOACTION,FAILUREeERROR(quandoProcessorTransactionIdestá presente).- O callback
onErroré acionado quando oActionCodeéERRORsemProcessorTransactionId, ou em respostas inesperadas.
Código-fonte do mpiHelpers.js (sandbox)
O código abaixo é o conteúdo completo do mpiHelpers.js disponibilizado no ambiente de sandbox (https://mpisandbox.braspag.com.br/Scripts/V3/mpiHelpers.js). Ele fornece os utilitários getBrowserInfo, getOrderBuilder e as constantes de moeda e canal usados nas etapas anteriores.
O
mpiHelpers.jsserá usado na Etapa 4 – Carregar e inicializar o script
const MPIHelpers = (function () {
"use strict";
const _currencyIsoCodes = {
BRL: "986",
USD: "840",
MXN: "484",
COP: "170",
CLP: "152",
ARS: "032",
PEN: "604",
EUR: "978",
PYN: "600",
UYU: "858",
VEB: "862",
VEF: "937",
GBP: "826"
};
const _orderChannels = {
ECOMMERCE: "S",
MOTO: "M",
RETAIL: "R",
MOBILE_DEVICE: "P",
TABLET: "T"
};
const _orderBuilder = {
_order: {
"OrderDetails": {
"OrderChannel": "S"
},
"Consumer": {
"Account": {},
"ShippingAddress": {},
"BillingAddress": {}
},
"Cart": []
},
withTransaction: function (transactionId) {
this._order.OrderDetails.TransactionId = transactionId;
return this;
},
withOrderNumber: function (orderNumber) {
this._order.OrderDetails.OrderNumber = orderNumber;
return this;
},
withCurrency: function (currencyCode) {
this._order.OrderDetails.CurrencyCode = currencyCode;
return this;
},
withChannel: function (orderChannel) {
this._order.OrderDetails.OrderChannel = orderChannel;
return this;
},
withOrderDetails: function (orderNumber, currencyCode, orderChannel) {
this.withOrderNumber(orderNumber);
this.withCurrency(currencyCode);
this.withChannel(orderChannel);
return this;
},
withCard: function (cardNumber, expirationMonth, expirationYear) {
this._order.Consumer.Account.AccountNumber = cardNumber;
this._order.Consumer.Account.ExpirationMonth = expirationMonth;
this._order.Consumer.Account.ExpirationYear = expirationYear;
return this;
},
withEmail1: function (email1) {
this._order.Consumer.Email1 = email1;
return this;
},
withEmail2: function (email2) {
this._order.Consumer.Email2 = email2;
return this;
},
withBillingAddress: function (fullname, addressLine1, addressLine2, city, state, postalCode, countryCode, phone) {
this._order.Consumer.BillingAddress.FullName = fullname;
this._order.Consumer.BillingAddress.Address1 = addressLine1;
this._order.Consumer.BillingAddress.Address2 = addressLine2;
this._order.Consumer.BillingAddress.City = city;
this._order.Consumer.BillingAddress.State = state;
this._order.Consumer.BillingAddress.PostalCode = postalCode;
this._order.Consumer.BillingAddress.CountryCode = countryCode;
this._order.Consumer.BillingAddress.Phone1 = phone;
return this;
},
withShippingAddress: function (fullname, addressLine1, addressLine2, city, state, postalCode, countryCode, phone) {
this._order.Consumer.ShippingAddress.FullName = fullname;
this._order.Consumer.ShippingAddress.Address1 = addressLine1;
this._order.Consumer.ShippingAddress.Address2 = addressLine2;
this._order.Consumer.ShippingAddress.City = city;
this._order.Consumer.ShippingAddress.State = state;
this._order.Consumer.ShippingAddress.PostalCode = postalCode;
this._order.Consumer.ShippingAddress.CountryCode = countryCode;
this._order.Consumer.ShippingAddress.Phone1 = phone;
return this;
},
withShippingAddressAsBillingAddress() {
this.withShippingAddress(
this._order.Consumer.BillingAddress.FullName,
this._order.Consumer.BillingAddress.Address1,
this._order.Consumer.BillingAddress.Address2,
this._order.Consumer.BillingAddress.City,
this._order.Consumer.BillingAddress.State,
this._order.Consumer.BillingAddress.PostalCode,
this._order.Consumer.BillingAddress.CountryCode,
this._order.Consumer.BillingAddress.Phone1
);
return this;
},
withCartItem: function (name, description, sku, quantity, price) {
const cartItem = this.buildCartItem(name, description, sku, quantity, price);
this._order.Cart.push(cartItem);
return this;
},
withCartItems: function (...cartItens) {
this._order.Cart.push(...cartItens);
return this;
},
buildCartItem: function (name, description, sku, quantity, price) {
return {
"Name": name,
"Description": description,
"SKU": sku,
"Quantity": quantity,
"Price": price
};
},
build: function () {
return this._order;
}
};
function _getBrowserInfo() {
const screenWidth = window && window.screen ? window.screen.width : '';
const screenHeight = window && window.screen ? window.screen.height : '';
const colorDepth = window && window.screen ? window.screen.colorDepth : '';
const userAgent = window && window.navigator ? window.navigator.userAgent : '';
const javaEnabled = window && window.navigator && window.navigator.javaEnabled() ? 'Y' : 'N';
let language = '';
if (window && window.navigator) {
language = window.navigator.language ? window.navigator.language : window.navigator.browserLanguage;
}
const timeZoneOffset = new Date().getTimezoneOffset();
return {
userAgent: userAgent,
screenWidth: screenWidth,
screenHeight: screenHeight,
colorDepth: colorDepth,
timeZoneOffset: timeZoneOffset,
language: language,
javaEnabled: javaEnabled,
javascriptEnabled: 'Y'
};
}
return {
getBrowserInfo: function () {
return _getBrowserInfo();
},
getOrderBuilder: function () {
return _orderBuilder;
},
Constants: {
getCurrencyISO: function () {
return _currencyIsoCodes;
},
getOrderChannels: function () {
return _orderChannels;
}
}
};
})();Pontos de atenção no
mpiHelpers.js:
getBrowserInfo()coletauserAgent,screenWidth,screenHeight,colorDepth,timeZoneOffset,languageejavaEnableddo navegador. O campojavascriptEnabledé sempre'Y'.getOrderBuilder()retorna o builder de pedido. Todos os métodoswith*são encadeáveis e terminam com.build().withShippingAddressAsBillingAddress()copia o endereço de cobrança para o de entrega sem necessidade de repetir os dados.buildCartItem()cria um item avulso para uso comwithCartItems(...items).
1.2 Configurar o script mpi.js
Neste passo você irá configurar o script mpi.js.
Chame MPI.load passando um objeto de configuração com os parâmetros e callbacks necessários:
MPI.load({
Environment: "SDB", // "SDB" para sandbox | "PRD" para produção
Debug: true, // true ativa os logs no console do navegador
// Acionado quando as dependências externas (Cardinal) são carregadas.
// Use para habilitar o botão de compra ou indicar que o checkout está pronto.
onLoadComplete: function () {
document.getElementById("btnPagar").disabled = false;
},
// Acionado quando Cardinal.setup é concluído e o script está pronto para uso.
// Só chame MPI.updateCard() depois deste evento.
onReady: function () {
console.log("MPI pronto.");
},
// Acionado em caso de erro durante o processo de autenticação.
// O objeto error contém: { Xid, Eci, ReturnCode, ReturnMessage, ReferenceId }
onError: function (error) {
console.error("Código:", error.ReturnCode);
console.error("Mensagem:", error.ReturnMessage);
},
// Acionado após o portador concluir o desafio.
// O objeto validationEvent contém: { TransactionId }
// Use o TransactionId para chamar a operação VALIDATE no back-end.
onValidationRequired: function (validationEvent) {
const transactionId = validationEvent.TransactionId;
enviarParaBackend({ transactionId: transactionId });
},
// Chamado imediatamente antes de executar MPI.updateCard().
// Deve retornar o número do cartão como string (somente dígitos).
cardNumberReader: function () {
return document.getElementById("cardNumber").value.replace(/\D/g, "");
}
});Parâmetros de configuração:
| Parâmetro | Tipo | Valores aceitos | Descrição |
|---|---|---|---|
Environment | string | "SDB" ou "PRD" | Ambiente de execução |
Debug | booleano | true ou false | Ativa os logs no console (debug) |
Callbacks de evento:
| Callback | Argumento recebido | Descrição |
|---|---|---|
onLoadComplete | — | Acionado quando as dependências estão carregadas. |
onReady | — | Acionado quando a inicialização do script é concluída. |
onError | { Xid, Eci, ReturnCode, ReturnMessage, ReferenceId } | Acionado quando ocorre um erro durante o processo. |
onValidationRequired | { TransactionId } | Acionado após o desafio. Use TransactionId para disparar o VALIDATE. |
cardNumberReader | — | Chamado pelo script para ler o número do cartão. Retorna uma string. |
Etapa 2 – AUTH: obter o access_token
access_tokenExecute esta operação exclusivamente no back-end. Nunca exponha o
access_tokenno front-end.
Requisição
Método: POST
URL de sandbox: https://mpisandbox.braspag.com.br/v3/auth/token
URL de produção: https://mpi.braspag.com.br/v3/auth/token
Headers:
Authorization: Basic <credencial_em_base64>
Content-Type: application/json
Body:
{
"EstablishmentCode": "1111111111",
"MerchantName": "NOME DA LOJA",
"MCC": "0000"
}Campos da requisição:
| Campo | Tipo | Obrigatório | Tamanho | Descrição |
|---|---|---|---|---|
EstablishmentCode | numérico | Sim | 10 | Código do estabelecimento na adquirente |
MerchantName | string | Sim | 1–25 | Nome do estabelecimento |
MCC | numérico | Sim | 4 | Categoria do estabelecimento (MCC) |
Resposta
{
"access_token": "<access_token>",
"token_type": "bearer",
"expires_in": "1200"
}[
{
"Code": 605,
"Message": "Establishment code is a mandatory parameter"
}
][
{
"Code": 606,
"Message": "Merchant name is a mandatory parameter"
}
][
{
"Code": 607,
"Message": "MCC is a mandatory parameter"
}
][
{
"Code": 608,
"Message": "MCC must have 4 digits"
}
]Campos da resposta:
Campo | Tipo | Descrição |
|---|---|---|
| string | Token de acesso. Use em todas as chamadas seguintes. Não exponha o |
| string | Tipo do token. Valor fixo: |
| string | Tempo de validade do |
Erros comuns (400 Bad Request)
| Campo com erro | Cenário | Código de erro |
|---|---|---|
EstablishmentCode | Campo enviado vazio | 605 |
MerchantName | Campo enviado vazio | 606 |
MCC | Campo enviado vazio | 607 |
MCC | Valor não numérico (ex.: "XXXX") | 607 |
Etapa 3 – INIT: inicializar a sessão
Execute esta operação no back-end após obter o
access_token. Otokenretornado deve ser enviado ao front-end para inicializar o script MPI.Atenção: o
tokenretornado pelo INIT é diferente doaccess_token. Apenas otokenpode ser exposto no front-end. Não exponha oaccess_tokenno front-end.
Requisição
Método: POST
URL de sandbox: https://mpisandbox.braspag.com.br/v3/3ds/init
URL de produção: https://mpi.braspag.com.br/v3/3ds/init
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Body:
{
"orderNumber": "ORD-0000123",
"currency": "986",
"amount": "1000"
}Campos da requisição:
Campo | Tipo | Obrigatório | Tamanho | Intervalo | Descrição |
|---|---|---|---|---|---|
| string | Sim | 1–50 | — | Número do pedido |
| string | Sim | 3 |
| Código ISO da moeda |
| numérico | Não | — | 0–99.999.999.999 | Valor total do pedido em centavos. |
Resposta
{
"referenceId": "f49f78fc-4427-439b-888c-dfa78a207bca",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwZWJlYjA1My1mZTYxLTRhYWQtYWIyYi0yOGE3MzQxOTQyNzMiLCJpYXQiOjE3ODIxNTg2ODcsImlzcyI6IjYwOTk1OGJiZjc0MzQ0NmUwMWNkYzAzMiIsIk9yZ1VuaXRJZCI6IjYwOTk1OGJiMGQ2MTkzN2NlMjM4ODlmYiIsIlBheWxvYWQiOiJ7XCJPcmRlckRldGFpbHNcIjp7XCJPcmRlck51bWJlclwiOlwiMTIzNDU2XCIsXCJBbW91bnRcIjpcIjEwMDBcIixcIkN1cnJlbmN5Q29kZVwiOlwiOTg2XCJ9fSIsIk9iamVjdGlmeVBheWxvYWQiOmZhbHNlLCJleHAiOjE3ODIxNTk1ODcsIlJlZmVyZW5jZUlkIjoiZjQ5Zjc4ZmMtNDQyNy00MzliLTg4OGMtZGZhNzhhMjA3YmNhIn0.rVvMS5r3rkOKNiDTOOLuz23amwkDbQ84Af3Agw1zCd4"
}[
{
"Code": "OrderNumber",
"Message": "'Order Number' must not be empty."
}
]Campos da resposta:
| Campo | Tipo | Descrição |
|---|---|---|
referenceId | string | Identificador de referência. Use no corpo da requisição do ENROLL. |
token | string | Token para inicialização do script no front-end via MPI.init. |
Erros comuns (400 Bad Request)
| Campo com erro | Cenário |
|---|---|
orderNumber | Campo enviado vazio |
Etapa 4 – Carregar e inicializar o script
Após o back-end executar o INIT e retornar referenceId e token, envie esses valores ao front-end.
Atenção: o
tokenretornado pelo INIT é diferente doaccess_token. Apenas otokenpode ser exposto no front-end. Não exponha oaccess_tokenno front-end.
4.1 Inicializar o script
O trecho abaixo é um exemplo de como fazer a inicialização do script, adapte com os dados necessários:
// Chame o endpoint do seu back-end que executa o INIT e retorna referenceId e token
fetch("/api/ENDPOINTDALOJA", { method: "POST" })
.then(response => response.json())
.then(data => {
// data.referenceId e data.token são retornados pela operação INIT
MPI.init(data.referenceId, data.token);
// Aguarde o callback onReady antes de prosseguir.
});A assinatura do método é
MPI.init(referenceId, token). A ordem dos parâmetros é obrigatória.
4.2 Atualizar o cartão e enviar o pedido
Chame MPI.updateCard() antes de enviar o pedido ao back-end. O método invoca o cardNumberReader definido na configuração e não retorna valor.
Sempre chame MPI.updateCard() novamente quando o número do cartão puder ter mudado entre tentativas.
O método envia o cardNumber atual para o Cardinal e o associa à sessão ativa — sem essa atualização, a autenticação pode usar um número desatualizado. Isso se aplica principalmente quando o comprador troca de cartão durante a mesma sessão.
Nesses casos, chame MPI.updateCard() antes de um novo ENROLL para manter a sessão sincronizada.
document.getElementById("btnPagar").addEventListener("click", function () {
// 1. Atualiza os dados do cartão no script
MPI.updateCard();
// 2. Coleta os dados do navegador
const browserInfo = MPIHelpers.getBrowserInfo();
// 3. Envia ao endpoint do seu back-end para executar o ENROLL
fetch("/api/ENDPOINTDALOJA", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
orderNumber: "ORD-0000123",
// ... demais campos do pedido
browserInfo: browserInfo
})
})
.then(response => response.json())
.then(data => {
if (data.status === 2) {
// Desafio necessário
const order = construirObjetoPedido();
MPI.challenge(
{
acsUrl: data.challenge.acsUrl,
payload: data.challenge.pareq,
transactionId: data.challenge.transactionId
},
order
);
}
// Status 0 ou 1: tratar no back-end
});
});Use MPIHelpers.getBrowserInfo() para coletar automaticamente os dados obrigatórios do objeto BrowserInfo:
const browserInfo = MPIHelpers.getBrowserInfo();
// Retorna:
// {
// userAgent: "Mozilla/5.0 ...",
// screenWidth: 1280,
// screenHeight: 720,
// colorDepth: 24,
// timeZoneOffset: 180,
// language: "pt-BR",
// javaEnabled: "N",
// javascriptEnabled: "Y"
// }Você também pode consultar moedas e canais aceitos via MPIHelpers.Constants:
// Retorna o mapa de moedas: { BRL: "986", USD: "840", EUR: "978", ... }
const moedas = MPIHelpers.Constants.getCurrencyISO();
// Retorna os canais aceitos: { ECOMMERCE: "S", MOTO: "M", RETAIL: "R", MOBILE_DEVICE: "P", TABLET: "T" }
const canais = MPIHelpers.Constants.getOrderChannels();Etapa 5 – ENROLL: autenticar o cartão
Execute esta operação no back-end. Ela realiza a matrícula do portador e a autenticação do cartão no protocolo 3DS.
Veja os principais cenários de autenticação suportados pela API, com exemplos de comportamento esperados para cada tipo de requisição:
| Cenário | Tipo de autenticação | Descrição | Resultado esperado |
|---|---|---|---|
| Cenário 1 | Sem desafio (campos obrigatórios) | Simula uma autenticação enviando apenas os campos obrigatórios. | Status = 1 |
| Cenário 2 | Sem desafio (campos obrigatórios + opcionais) | Simula uma autenticação com dados adicionais para enriquecer a análise de risco. | Status = 1 |
| Cenário 3 | Sem desafio (companhias aéreas) | Simula uma autenticação sem desafio específica para companhias aéreas. | Status = 1 |
| Cenário 4 | Sem desafio (transações recorrentes) | Simula uma autenticação sem desafio específica para transações recorrentes. | Status = 1 |
| Cenário 5 | Com desafio | Simula uma autenticação que exige desafio (ex.: step-up). | Status = 2 com objeto challenge |
| Cenário 6 | Falha na autenticação | Simula uma falha no processo de autenticação. | Status = 0 |
| Cenário 7 | Data Only | Coleta apenas dados do portador sem gerar desafio. | Status = 1 sem objeto challenge |
Cartões de teste sem desafio
Para simular autenticações sem desafio, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
4000000000002701 | VISA | Success | Autenticação sem desafio e portador autenticado com sucesso. | 1 |
4000000000002925 | VISA | Failure | Autenticação sem desafio e portador autenticado com falha. | 0 |
Cartões de teste com desafio
Para simular autenticações com desafio, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
4000000000002503 5200000000002151 | Visa Master Elo | Success | Autenticação com desafio e portador autenticado com sucesso. | 2 |
4000000000002370 | Visa Master | Failure | Autenticação com desafio e portador autenticado com falha. | 0 |
4000000000002420 | Visa Master | Unenrolled | Autenticação com desafio indisponível no momento. | 0 |
4000000000002644 | Visa | Error | Erro de sistema durante a etapa de autenticação. | 0 |
Cartões de teste para DataOnly
Para simular autenticações via DataOnly, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
5200000000002805 | Mastercard | Success | Autenticação via DataOnly | 0 |
Requisição
Método: POST
URL de sandbox: https://mpisandbox.braspag.com.br/v3/3ds/enroll
URL de produção: https://mpi.braspag.com.br/v3/3ds/enroll
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Cenário 1 – Sem desafio (campos obrigatórios)
Veja um exemplo de requisição que simula uma autenticação sem desafio enviando apenas os campos obrigatórios.
Para ter o Status = 1, use o número de cartão de teste 4000000000002701.
{
"TransactionMode": "S",
"MerchantUrl": "https://www.sualojanome.com.br",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": true,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002701",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "123.456.789-09",
"Name": "João da Silva",
"PhoneNumber": "11999990001",
"Email": "[email protected]",
"Street1": "Av. Paulista, 1000",
"Street2": "Apto 42",
"City": "São Paulo",
"State": "SP",
"ZipCode": "01310-100",
"Country": "BR"
},
"CartItems": [
{
"Name": "Produto A",
"Description": "Descrição do produto A",
"Sku": "SKU-001",
"Quantity": 1,
"UnitPrice": 1000
}
],
"DeviceInfo": {
"IpAddress": "200.200.200.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "c00a2117-0da5-454b-8bcb-63774b46cd4f",
"Xid": "AJkBBkhgQQAAAE4gSEJydQAAAAA=",
"Eci": "05",
"Cavv": "AJkBBkhgQQAAAE4gSEJydQAAAAA="
},
"Status": 1,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Cenário 2 – Sem desafio (campos obrigatórios e opcionais)
Veja um exemplo de requisição que simula uma autenticação sem desafio enviando também os campos opcionais UserAccount, ShipTo e campos avançados de Order para enriquecer a análise de risco.
Para ter o Status = 1, use o número de cartão de teste 4000000000002701.
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"MerchantNewCustomer": "true",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": false,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002701",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"ShipTo": {
"Name": "John Doe Jr.",
"PhoneNumber": "555-0002",
"Email": "[email protected]",
"Street1": "Rua Bem Longe",
"Street2": "Casa 3",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222223-23",
"Country": "BR"
},
"CartItems": [
{
"Name": "Produto A",
"Description": "Descrição do produto A",
"Sku": "SKU-001",
"Quantity": 1,
"UnitPrice": 1000
}
],
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY",
"CountLast24Hours": 2,
"CountLast6Months": 15,
"CountLast1Year": 38,
"CardAttemptsLast24Hours": 1
},
"UserAccount": {
"Guest": false,
"CreatedDate": "2020-01-10",
"ChangedDate": "2025-06-01",
"PasswordChangedDate": "2025-06-01",
"AuthenticationMethod": "02"
},
"MerchantDefinedData": {
"1": "valor_customizado_1",
"2": "valor_customizado_2"
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "e4198bcd-5024-4909-8885-5c924149237f",
"Xid": "AJkBBkhgQQAAAE4gSEJydQAAAAA=",
"Eci": "05",
"Cavv": "AJkBBkhgQQAAAE4gSEJydQAAAAA="
},
"Status": 1,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Cenário 3 – Sem desafio (companhias aéreas)
Veja um exemplo de requisição para companhias aéreas que simula uma autenticação sem desafio enviando apenas os campos obrigatórios. Para ter o Status = 1, use o número de cartão de teste 4000000000002701.
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 700000,
"Installments": 1,
"ShipToSameAsBillTo": false,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002701",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"Airline": {
"NumberOfPassengers": 2,
"PassportCountry": "BR",
"PassportNumber": "AA123456",
"TravelLegs": [
{
"Carrier": "LA",
"DepartureDate": "2026-09-01",
"Origin": "GRU",
"Destination": "JFK"
}
],
"Passengers": [
{
"Name": "João da Silva",
"TicketPrice": 350000
},
{
"Name": "Maria da Silva",
"TicketPrice": 350000
}
]
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "b1d0c4ff-0720-437d-8125-0c8b50c067a1",
"Xid": "AJkBBkhgQQAAAE4gSEJydQAAAAA=",
"Eci": "05",
"Cavv": "AJkBBkhgQQAAAE4gSEJydQAAAAA="
},
"Status": 1,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Cenário 4 - Sem desafio (transações recorrentes)
Para enviar simular uma autenticação sem desafio para transações recorrentes é necessário enviar os campos necessários no objeto Recurring e usar o cartão de teste 4000000000002701.
No fluxo de pagamentos recorrentes, apenas a primeira transação da série é submetida ao processo de autenticação.
As transações subsequentes da mesma recorrência não são autenticadas novamente, sendo enviadas diretamente para autorização.
Veja um exemplo de requisição que simula uma autenticação sem desafio para transações recorrentes:
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": true,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002701",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"CartItems": [
{
"Name": "Name412f7da6-a1d5-45f8-ab8a-7011b9522c4e",
"Description": "Descriptionbde9d2f3-2e05-4183-a06b-44d4ece3ae08",
"Sku": "Sku54685c5a-2c7e-44a4-9a0e-ef1bdfe324b1",
"Quantity": 241,
"UnitPrice": 46
},
{
"Name": "Nameef810b54-de83-4f5a-9390-6402715d877d",
"Description": "Descriptiond1b4947f-14f6-4a32-a076-a2d1c8f46aa9",
"Sku": "Sku8cee605b-b222-4936-9ad7-cd5188925015",
"Quantity": 160,
"UnitPrice": 24
},
{
"Name": "Name40b447e9-2a22-4ce8-b90b-f803b07bc6b5",
"Description": "Description584b5011-e969-41ff-94d4-5b68f073b3a5",
"Sku": "Sku8ad6c9e3-1676-4476-9208-ed61f650aadb",
"Quantity": 155,
"UnitPrice": 42
}
],
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "FingerPrinte659bbd0-f2d6-491d-8fd0-f2d179ab42e6",
"Provider": "Provider01c89ed4-4956-468c-9eea-2e7dd8a0409a"
},
{
"FingerPrint": "FingerPrint89d86f03-a064-4bae-b1fb-cb46984088d1",
"Provider": "Provider76640b49-b702-43f2-b78d-90796002d2f9"
},
{
"FingerPrint": "FingerPrintd7bde495-6a28-4feb-a515-afacaf608b31",
"Provider": "Providerdcbaa001-980b-4bcd-b84e-86ced8a71067"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"MerchantDefinedData": {
"1": "valuec0b65672-17c3-4e9b-a1fa-9b725f9c95dc",
"2": "valuee7e1b70f-01ea-4742-9738-99e99eac1863",
"3": "value9c78f1f9-1728-426c-9ac7-52e330461511"
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "250x400",
"Recurring": {
"EndDate": "2026-12-31",
"Frequency": 1,
"OriginalPurchaseDate": "2026-01-01",
"RecurringInfos": {
"Type": 1,
"ValidationIndicator": 1,
"MaximumAmount": "10.00",
"ReferenceNumber": "ORD-0000123-001",
"Occurrence": "06",
"NumberOfPayments": "12",
"AmountType": "1"
}
},
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "2b86c48d-b0a4-43a1-a1ca-86539ecdd394",
"Xid": "AJkBBkhgQQAAAE4gSEJydQAAAAA=",
"Eci": "05",
"Cavv": "AJkBBkhgQQAAAE4gSEJydQAAAAA="
},
"Status": 1,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Cenário 5 – Com desafio
Veja um exemplo de requisição que simula uma autenticação com desafio. Para ter o Status = 2 com o objeto challenge, use o número de cartão de teste 4000000000002503.
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": true,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002503",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"CartItems": [
{
"Name": "Produto A",
"Description": "Descrição do produto A",
"Sku": "SKU-001",
"Quantity": 1,
"UnitPrice": 1000
}
],
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": {
"AcsUrl": "https://1merchantacsstag.cardinalcommerce.com/MerchantACSWeb/creq.jsp",
"Pareq": "eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMi4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJlOTljM2IwNS1mZGZiLTRkNGMtOTdjNS1lMTY5Mjg1OWM1Y2YiLCJhY3NUcmFuc0lEIjoiMjdiYTk3ZmMtMDk4MS00YTZkLWFhYTEtZTIwMjNjNWQzNjk5IiwiY2hhbGxlbmdlV2luZG93U2l6ZSI6IjAyIn0",
"TransactionId": "2MfUuV2lgIgspJ1gMBV1"
},
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "1dacc363-f9bb-4dc6-bb49-bc613c7e1d17",
"Xid": null,
"Eci": null,
"Cavv": null
},
"Status": 2,
"Reason": {
"Code": "475",
"Message": "Enrolled"
}
}Cenário 6 – Falha na autenticação
Veja um exemplo de requisição que simula uma falha na autenticação. Para ter o Status = 0, use o número de cartão de teste 4000000000002925.
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": true,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002925",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"CartItems": [
{
"Name": "Produto A",
"Description": "Descrição do produto A",
"Sku": "SKU-001",
"Quantity": 1,
"UnitPrice": 1000
}
],
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"AuthNotifyOnly": false,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "feb7d684-b8ad-4107-a402-b2816dd51b22",
"Xid": null,
"Eci": "07",
"Cavv": null
},
"Status": 0,
"Reason": {
"Code": "476",
"Message": "Customer cannot be authenticated"
}
}Cenário 7 – Data Only
Veja um exemplo de requisição que simula uma autenticação via Data Only sem desafio enviando apenas os campos obrigatórios. Para ter o Status = 1, use o número de cartão de teste 4000000000002701.
{
"TransactionMode": "S",
"MerchantUrl": "https://samplemerchant.org",
"OrderNumber": "ORD-0000123",
"Currency": "BRL",
"TotalAmount": 1000,
"Installments": 1,
"ShipToSameAsBillTo": true,
"Card": {
"PaymentMethod": "credit",
"CardNumber": "4000000000002701",
"ExpirationMonth": 3,
"ExpirationYear": 2029
},
"BillTo": {
"CustomerId": "999888777-94",
"Name": "John Doe",
"PhoneNumber": "555-0001",
"Email": "[email protected]",
"Street1": "Av. Batatinha Quando Nasce",
"Street2": "Batata",
"City": "Rio de Janeiro",
"State": "RJ",
"ZipCode": "222222-22",
"Country": "BR"
},
"DeviceInfo": {
"IpAddress": "127.0.0.1",
"Channel": "Browser",
"Devices": [
{
"FingerPrint": "<fingerprint_id>",
"Provider": "cardinal"
}
]
},
"Order": {
"ProductCode": "PHY"
},
"AuthNotifyOnly": true,
"ChallengeWindowSize": "390x400",
"BrowserInfo": {
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ScreenWidth": "1280",
"ScreenHeight": "720",
"ColorDepth": "32",
"TimeZoneOffset": "180",
"Language": "pt-BR",
"JavaEnabled": "N",
"JavaScriptEnabled": "Y"
}
}{
"Challenge": null,
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "7d6cb131-d09c-4b00-bb69-122225082529",
"Xid": "AJkBBkhgQQAAAE4gSEJydQAAAAA=",
"Eci": "05",
"Cavv": "AJkBBkhgQQAAAE4gSEJydQAAAAA="
},
"Status": 1,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Parâmetros da requisição ENROLL
A tabela a seguir apresenta todos os parâmetros disponíveis para envio na requisição da etapa ENROLL. Envie obrigatoriamente os parâmetros marcados como obrigatórios. Recomendamos o envio de todos os parâmetros para aumentar a chance de ter uma autenticação sem desafio (frictionless).
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
orderNumber | string | Sim | Número do pedido |
currency | string | Sim | Moeda. Valor: BRL |
card.cardNumber | string | Sim | Número do cartão |
card.expirationMonth | numérico | Não | Mês de validade |
card.expirationYear | numérico | Não | Ano de validade |
card.paymentMethod | string | Condicional | Tipo do cartão. Obrigatório para cartões múltiplos (crédito e débito no mesmo cartão). |
card.cardAlias | string | Não | Apelido do cartão |
card.defaultCard | booleano | Não | true se é o cartão padrão do comprador na loja |
card.cardAddedDate | data | Não | Data em que o cartão foi cadastrado na loja (formato YYYY-MM-DD) |
billTo.name | string | Sim | Nome do portador |
billTo.phoneNumber | string | Sim | Número de celular |
billTo.email | string | Sim | Endereço de e-mail |
billTo.street1 | string | Sim | Primeira linha do endereço |
billTo.street2 | string | Não | Segunda linha do endereço |
billTo.city | string | Sim | Cidade |
billTo.state | string | Sim | Estado (sigla) |
billTo.zipCode | string | Sim | CEP |
billTo.country | string | Sim | País (código ISO, 2 caracteres) |
billTo.customerId | string | Não | CPF ou documento do comprador |
browserInfo.userAgent | string | Sim | User agent do navegador |
browserInfo.screenWidth | string | Sim | Largura da tela em pixels |
browserInfo.screenHeight | string | Sim | Altura da tela em pixels |
browserInfo.colorDepth | string | Sim | Profundidade de cor (bits) |
browserInfo.timeZoneOffset | string | Sim | Deslocamento de fuso horário em minutos |
browserInfo.language | string | Sim | Idioma do navegador (ex.: pt-BR) |
browserInfo.javaEnabled | string | Sim | Java habilitado: "Y" ou "N" |
browserInfo.JavaScriptEnabled | string | Sim | JavaScript habilitado: "Y" ou "N" |
transactionMode | string | Não | Canal da transação: M (MOTO), R (varejo), S (e-commerce), P (mobile), T (tablet) |
merchantUrl | string | Não | URL do site do estabelecimento |
merchantNewCustomer | string | Não | Indica se é novo comprador: "true" ou "false" |
totalAmount | numérico | Não | Valor total do pedido em centavos |
installments | numérico | Não | Número de parcelas |
shipToSameAsBillTo | booleano | Não | true se o endereço de entrega é igual ao de cobrança; false para inserir outro endereço de entrega em ShipTo |
shipTo.name | string | Não | Nome do destinatário |
shipTo.phoneNumber | string | Não | Número de celular |
shipTo.email | string | Não | Endereço de e-mail |
shipTo.street1 | string | Não | Primeira linha do endereço |
shipTo.street2 | string | Não | Segunda linha do endereço |
shipTo.city | string | Não | Cidade |
shipTo.state | string | Não | Estado (sigla) |
shipTo.zipCode | string | Não | CEP do endereço de entrega |
shipTo.country | string | Não | País (código ISO, 2 caracteres) |
shipTo.shippingMethod | string | Não | Método de envio: lowcost (econômico), sameday (mesmo dia), oneday (próximo dia), twoday (dois dias), threeday (três dias), pickup (retirada na loja), other (outros), none (sem envio) |
shipTo.firstUsageDate | data | Não | Data da primeira utilização do endereço de entrega (formato YYYY-MM-DD) |
cartItems.name | string | Não | Nome do item |
cartItems.description | string | Não | Descrição do item |
cartItems.sku | string | Não | SKU do item |
cartItems.quantity | numérico | Não | Quantidade |
cartItems.unitPrice | numérico | Não | Valor unitário do item em centavos |
deviceInfo.ipAddress | string | Não | Endereço IP do dispositivo |
deviceInfo.channel | string | Não | Canal da transação. Valores aceitos: Browser, SDK, 3RI |
deviceInfo.devices.fingerPrint | string | Não | Identificador retornado pelo provedor de Device Fingerprint |
deviceInfo.devices.provider | string | Não | Nome do provedor. Valores aceitos: cardinal, inauth, threatmetrix |
order.productCode | string | Não | Código do produto no estabelecimento |
order.countLast24Hours | numérico | Não | Pedidos do comprador nas últimas 24 horas |
order.countLast6Months | numérico | Não | Pedidos do comprador nos últimos 6 meses |
order.countLast1Year | numérico | Não | Pedidos do comprador no último ano |
order.cardAttemptsLast24Hours | numérico | Não | Transações com o mesmo cartão nas últimas 24 horas |
order.marketingOptin | string | Não | "true" se o comprador aceitou receber ofertas de marketing |
order.marketingSource | string | Não | Origem da campanha de marketing |
userAccount.guest | booleano | Não | true se o comprador não possui cadastro na loja |
userAccount.createdDate | string | Não | Data de criação da conta (formato YYYY-MM-DD) |
userAccount.changedDate | string | Não | Data da última alteração na conta (formato YYYY-MM-DD) |
userAccount.passwordChangedDate | string | Não | Data da última alteração de senha (formato YYYY-MM-DD) |
userAccount.authenticationMethod | string | Não | Método de autenticação na loja: 01 (sem autenticação), 02 (login da loja), 03 (ID federado), 04 (autenticador FIDO) |
userAccount.authenticationProtocol | string | Não | Protocolo de login utilizado na loja |
userAccount.authenticationTimestamp | data e hora | Não | Data e hora do login na loja |
airline.travelLegs.carrier | string | Não | Código IATA da companhia aérea |
airline.travelLegs.departureDate | string | Não | Data de partida (formato YYYY-MM-DD) |
airline.travelLegs.origin | string | Não | Código IATA do aeroporto de origem |
airline.travelLegs.destination | string | Não | Código IATA do aeroporto de destino |
airline.passengers.name | string | Não | Nome do passageiro |
airline.passengers.ticketPrice | numérico | Não | Valor da passagem em centavos |
airline.numberOfPassengers | numérico | Não | Total de passageiros |
airline.passportCountry | string | Não | País emissor do passaporte (código ISO) |
airline.passportNumber | string | Não | Número do passaporte |
recurring.endDate | data | Não | Data de término da recorrência (formato YYYY-MM-DD) |
recurring.frequency | numérico | Não | Frequência: 1 (mensal), 2 (bimestral), 3 (trimestral), 4 (quadrimestral), 6 (semestral), 12 (anual) |
recurring.originalPurchaseDate | data | Não | Data da primeira transação que originou a recorrência |
recurring.recurringInfos.type | string | Não | Tipo do pagamento recorrente: 1 (primeira transação), 2 (subsequente), 3 (modificação), 4 (cancelamento) |
recurring.recurringInfos.validationIndicator | string | Não | Indica se foi validado: 0 (não validado), 1 (validado) |
recurring.recurringInfos.maximumAmount | string | Não | Valor máximo acordado com o titular |
recurring.recurringInfos.referenceNumber | string | Não | Número de referência exclusivo da recorrência |
recurring.recurringInfos.occurrence | string | Não | Frequência: 01 (diário), 02 (2x por semana), 03 (semanal), 04 (a cada 10 dias), 05 (quinzenal), 06 (mensal), 07 (bimestral), 08 (trimestral), 09 (quadrimestral), 10 (semestral), 11 (anual), 12 (não programado) |
recurring.recurringInfos.numberOfPayments | string | Não | Total de pagamentos durante a assinatura |
recurring.recurringInfos.amountType | string | Não | Tipo de valor: 1 (fixo), 2 (máximo) |
merchantDefinedData.1 | string | Não | Dados adicionais definidos pelo lojista |
merchantDefinedData.2 | string | Não | Dados adicionais definidos pelo lojista |
merchantDefinedData.3 | string | Não | Dados adicionais definidos pelo lojista |
authNotifyOnly | booleano | Não | true para autenticação no modo somente notificação (sem interação com o portador) |
brandEstablishmentCode | string | Não | Código de estabelecimento da bandeira |
challengeWindowSize | string | Não | Tamanho da janela de desafio: "250x400", "390x400", "600x400", "500x600" ou "FullScreen" |
Resposta ENROLL (200 OK)
Veja os campos retornados na resposta da operação ENROLL:
| Campo | Tipo | Descrição |
|---|---|---|
status | numérico | Resultado da autenticação. Consulte a tabela de status. |
Reason.Code | string | Código do motivo. Veja Códigos de motivo. |
Reason.Message | string | Mensagem do motivo. |
Challenge.AcsUrl | string | URL do Access Control Server (ACS) para exibição do desafio |
Challenge.Pareq | string | Requisição de autenticação do portador (Payer Auth Request) |
Challenge.TransactionId | string | Identificador da transação |
Authentication.Xid | string | XID da autenticação |
Authentication.Eci | string | Indicador ECI |
Authentication.Cavv | string | CAVV da autenticação |
Status da autenticação
Veja os possíveis status da autenticação:
| Status | Significado | Ação recomendada |
|---|---|---|
0 | Não autenticado | Avalie o ECI retornado para decidir se prossegue com a transação. Consulte a tabela de ECI. |
1 | Autenticado | Prossiga para a autorização da transação. |
2 | Desafio necessário | Exiba o desafio ao portador. Consulte a Etapa 6. |
Erros comuns (400 Bad Request)
Veja
| Campo com erro | Cenário |
|---|---|
ExpirationMonth | Valor fora do intervalo permitido (1–12) |
Etapa 6 – Exibir o desafio
Esta etapa se aplica apenas quando o ENROLL retornar status = 2.
6.1 Construir o objeto de pedido com MPIHelpers
Use MPIHelpers.getOrderBuilder() para montar o objeto necessário para MPI.challenge. Os métodos são encadeáveis:
const order = MPIHelpers.getOrderBuilder()
// Dados do pedido: número, moeda (código ISO) e canal
.withOrderDetails("ORD-0000123", "986", "S")
// ID da transação retornado pelo ENROLL (campo challenge.transactionId)
.withTransaction("<transactionId retornado pelo ENROLL>")
// Dados do cartão: número, mês e ano de validade
.withCard("4000000000002503", 3, 2029)
// E-mail do comprador
.withEmail1("[email protected]")
.withEmail2("[email protected]") // opcional
// Endereço de cobrança
.withBillingAddress(
"João da Silva",
"Av. Paulista, 1000",
"Apto 42",
"São Paulo",
"SP",
"01310-100",
"BR",
"11999990001"
)
// Endereço de entrega (se diferente do de cobrança)
.withShippingAddress(
"Maria da Silva",
"Rua das Flores, 500",
"Casa 3",
"Campinas",
"SP",
"13010-050",
"BR",
"11999990002"
)
// Ou use o endereço de cobrança como entrega:
// .withShippingAddressAsBillingAddress()
// Itens do carrinho: nome, descrição, SKU, quantidade, preço unitário (em centavos)
.withCartItem("Produto A", "Descrição do produto A", "SKU-001", 1, 1000)
.build();6.2 Chamar o método challenge
// Dados retornados pela operação ENROLL quando status = 2
const challengeData = {
acsUrl: enrollResponse.challenge.acsUrl,
payload: enrollResponse.challenge.pareq,
transactionId: enrollResponse.challenge.transactionId
};
MPI.challenge(challengeData, order);Após o portador concluir o desafio, o callback onValidationRequired é acionado com { TransactionId }. Envie esse valor ao back-end para executar o VALIDATE.
Etapa 7 – VALIDATE: validar a autenticação
Execute esta operação no back-end após o desafio. O resultado é definitivo — não existe novo desafio nessa etapa.
Requisição
Método: POST
URL de sandbox: https://mpisandbox.braspag.com.br/v3/3ds/validate
URL de produção: https://mpi.braspag.com.br/v3/3ds/validate
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Body:
{
"ordernumber": "ORD-0000123",
"currency": "BRL",
"totalamount": "1000",
"card": {
"cardnumber": "4000000000002503",
"expirationmonth": 3,
"expirationyear": 2029
},
"transactionId": "BR8llUtqlmzu40pzN9m1"
}{
"Authentication": {
"Version": "2.2.0",
"DirectoryServerTransactionId": "9a7c2937-148a-446a-9da8-3fffbe84f390",
"Xid": null,
"Eci": "07",
"Cavv": null
},
"Status": 0,
"Reason": {
"Code": "100",
"Message": "Success"
}
}Atenção: os campos do VALIDATE são enviados em minúsculas (
ordernumber,totalamount,cardnumber,expirationmonth,expirationyear), diferente do padrão PascalCase usado no ENROLL. Respeite o casing exato conforme os exemplos acima.
Campos da requisição:
| Campo | Tipo | Obrigatório | Tamanho | Descrição |
|---|---|---|---|---|
transactionId | string | Sim | 1–26 | Identificador da transação retornado pelo ENROLL |
ordernumber | string | Sim | 1–50 | Número do pedido |
currency | string | Sim | 3 | Código ISO da moeda (ex.: 986 para BRL) |
totalamount | numérico | Sim | — | Valor total do pedido em centavos |
card | Card | Sim | — | Dados do cartão. Consulte Card. |
billToCustomerId | string | Não | — | Documento de identificação do comprador |
Resposta VALIDATE (200 OK)
Possíveis campos retornados na resposta da operação VALIDATE:
| Campo | Tipo | Descrição |
|---|---|---|
status | numérico | Resultado da autenticação. Consulte a tabela de status. |
Reason.Code | string | Código do motivo. Veja Códigos de motivo. |
Reason.Message | string | Mensagem do motivo. |
Authentication.Version | string | Versão do protocolo 3DS |
Authentication.DirectoryServerTransactionId | string | Identificador da transação no Directory Server |
Authentication.Xid | string | XID da autenticação |
Authentication.Eci | string | Indicador ECI |
Authentication.Cavv | string | CAVV da autenticação |
Status retornados em VALIDATE
Status retornados na operação VALIDATE:
Os Status retornados são os mesmos da operação ENROLL. Apenas o status
2não é retornado na operação VALIDATE pois indica desafio.
| Status | Significado | Ação recomendada |
|---|---|---|
0 | Não autenticado | Avalie o ECI retornado para decidir se prossegue com a transação. Consulte a tabela de ECI. |
1 | Autenticado | Prossiga para a autorização da transação. |
Erros comuns (400 Bad Request)
Possíveis erros no retorno da operação VALIDATE:
| Campo com erro | Cenário |
|---|---|
currency | Valor com formato inválido ou moeda não suportada |
transactionId | Campo ausente ou vazio |
card | Objeto ausente ou cardnumber vazio |
Códigos de retorno e erros
Status HTTP
Veja os status HTTP, o significado e a ação recomendada no retorno de cada um:
| Código | Significado | Ação recomendada |
|---|---|---|
200 | Operação bem-sucedida | — |
400 | Falha de validação | Verifique os campos no objeto ErrorResult retornado na resposta. |
401 | Não autorizado | Regere o access_token e reinicie o processo. |
409 | Operação repetida ou fora de ordem | Respeite a sequência: AUTH → INIT → ENROLL → VALIDATE. |
500 | Erro interno do servidor | Tente novamente. Se o problema persistir, acione o suporte. |
Códigos de erro da operação AUTH
Veja os possíveis códigos de erro na operação AUTH:
| Código | Descrição |
|---|---|
605 | Código do estabelecimento não informado |
606 | Nome da loja não informado |
607 | MCC não informado ou inválido |
Códigos de motivo (Reason Codes)
Veja os possíveis códigos de motivos (Reason Codes):
| Código | Descrição |
|---|---|
100 | Sucesso |
101 | Campo obrigatório ausente |
102 | Valor de campo inválido |
234 | Erro de configuração |
475 | Portador matriculado |
476 | Portador não pode ser autenticado |
Para códigos não listados, a API retorna a mensagem
Unexpected error occurred. Acione o suporte Cielo para análise.
Status da autenticação
Veja os possíveis status da autenticação:
| Valor | Descrição |
|---|---|
0 | Não autenticado |
1 | Autenticado |
2 | Desafio |
Cartões de teste (sandbox)
Cartões de teste sem desafio
Para simular autenticações sem desafio, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
4000000000002701 | VISA | Success | Autenticação sem desafio e portador autenticado com sucesso. | 1 |
4000000000002925 | VISA | Failure | Autenticação sem desafio e portador autenticado com falha. | 0 |
Cartões de teste com desafio
Para simular autenticações com desafio, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
4000000000002503 5200000000002151 | Visa Master Elo | Success | Autenticação com desafio e portador autenticado com sucesso. | 2 |
4000000000002370 | Visa Master | Failure | Autenticação com desafio e portador autenticado com falha. | 0 |
4000000000002420 | Visa Master | Unenrolled | Autenticação com desafio indisponível no momento. | 0 |
4000000000002644 | Visa | Error | Erro de sistema durante a etapa de autenticação. | 0 |
Cartões de teste para DataOnly
Para simular autenticações via DataOnly, envie as requisições com um dos seguintes cartões de teste:
Cartão | Bandeira | Resultado | Cenário | Status |
|---|---|---|---|---|
5200000000002805 | Mastercard | Success | Autenticação via DataOnly | 0 |