Inicio
Documentação
Recursos
Parcerias
Comunidade

Recursos

Confira as atualizaçÔes das nossas soluçÔes e do funcionamento do sistema ou peça suporte técnico.

Parcerias

Conheça nosso programa para agĂȘncias ou desenvolvedores que oferecem serviços de integração e vendedores que desejam contratĂĄ-los.

Comunidade

Fique por dentro das Ășltimas novidades, peça ajuda a outros integradores e compartilhe seu conhecimento.

Como integrar 3DS com Checkout Transparente - Checkout Transparente - Mercado Pago Developers

Busca inteligente powered by OpenAI 

Como integrar 3DS com Checkout Transparente

Nesta documentação vocĂȘ encontrarĂĄ toda a informação necessĂĄria para realizar a integração com 3DS com Checkout Transparente. Para mais informaçÔes sobre como esse tipo de autenticação funciona, veja 3DS 2.0.

Importante
Para realizar a integração com 3DS, é preciso atender a determinados requisitos. Antes de avançar para os próximos passos, revise a seção Pré-requisitos e certifique-se de que todos sejam cumpridos.

Integrar com 3DS

A autenticação 3DS pode ser feita através de dois fluxos diferentes: com e sem Challenge, sendo estas etapas adicionais que o comprador deve cumprir para garantir sua identidade. A decisão de incluir ou não o Challenge depende do emissor do cartão e do perfil de risco da transação que estå sendo realizada.

Conheça também as integraçÔes via Checkout Bricks, uma forma de pagamento modular, segura e personalizåvel, que automatiza vårios dos processos descritos a seguir.

Para transaçÔes de baixo risco, as informaçÔes enviadas na finalização da compra são suficientes e as etapas adicionais do Challenge não são necessårias. Porém, para casos de alto risco de fraude, o Challenge é necessårio para verificar a identidade do comprador, o que aumenta a aprovação das transaçÔes com cartão.

Abaixo estão as etapas para realizar uma integração com 3DS.

  1. Utilize o Mercado Pago SDK JS no checkout para gerar o token do cartão de crédito.
  2. Em seguida, envie os dados do checkout junto com o token do cartĂŁo para o backend.
  3. Feito isso, faça uma chamada para criar um novo pagamento com os dados recebidos. O atributo three_d_secure_mode precisa ser enviado com um dos seguintes valores:
    1. not_supported: 3DS nĂŁo deve ser usado (Ă© o valor padrĂŁo).
    2. optional: 3DS pode ou não ser exigido, dependendo do perfil de risco da operação.
Importante
Recomendamos utilizar o valor optional na implementação do 3DS, por equilibrar segurança e a aprovação de transaçÔes.

Além disso, a captura do pagamento deve ser automåtica (capture=true) e a transação deve ser criada com o modo binårio desativado (binary mode= false), visto que a transação poderå ficar pendente aguardando que o comprador complete o Challenge.
          
<?php
  use MercadoPago\Client\Payment\PaymentClient;
  MercadoPagoConfig::setAccessToken("YOUR_ACCESS_TOKEN");

  $client = new PaymentClient();
  $request_options = new RequestOptions();
  $request_options->setCustomHeaders(["X-Idempotency-Key: <SOME_UNIQUE_VALUE>"]);

  $payment = $client->create([
    "transaction_amount" => <TRANSACTION_AMOUNT>,
    "token" => "CARD_TOKEN",
    "description" => "<DESCRIPTION>",
    "installments" => <INSTALLMENTS_NUMBER>,
    "payment_method_id" => "<PAYMENT_METHOD_ID>",
    "issuer_id" => "<ISSUER_ID>",
    "payer" => [
      "email" => $_POST['email']
    ],
    "three_d_secure_mode" => "optional"
  ], $request_options);
  echo implode($payment);
?>

        
          
MercadoPagoConfig.setAccessToken("<ENV_ACCESS_TOKEN>");
    PaymentClient client = new PaymentClient();
    PaymentCreateRequest createRequest =
        PaymentCreateRequest.builder()
            .transactionAmount(new BigDecimal(<TRANSACTION_AMOUNT>))
            .token("<CARD_TOKEN>")
            .description("<DESCRIPTION>")
            .installments(<INSTALLLMENTS_NUMBER>)
            .paymentMethodId("<PAYMENT_METHOD_ID>")
            .payer(
               PaymentPayerRequest.builder()
                 .email("<BUYER_EMAIL>")
                 .build()
            )
            .threeDSecureMode("optional")
            .build();
    client.create(createRequest);

        
          
using MercadoPago.Config;
using MercadoPago.Client.Payment;
using MercadoPago.Resource.Payment;
MercadoPagoConfig.AccessToken = "<ENV_ACCESS_TOKEN>";
var request = new PaymentCreateRequest
{
    TransactionAmount = <TRANSACTION_AMOUNT>,
    Token = "<CARD_TOKEN>",
    Description = "<DESCRIPTION>",
    Installments = <INSTALLLMENTS_NUMBER>,
    Payer = new PaymentPayerRequest
    {
        Email = "<BUYER_EMAIL>",
    },
    ThreeDSecureMode = "optional",
};
var client = new PaymentClient();
Payment payment = await client.CreateAsync(request);

        
          
import { MercadoPagoConfig, Payment } from 'mercadopago';

const client = new MercadoPagoConfig({ accessToken: '<ENV_ACCESS_TOKEN>' });
const payment = new Payment(client);

const body = {
  transaction_amount: <TRANSACTION_AMOUNT>,
  token: '<CARD_TOKEN>',
  description:  '<DESCRIPTION>',
  installments: <INSTALLMENTS_NUMBER>,
  payment_method_id: '<PAYMENT_METHOD_ID>',
  issuer_id: '<ISSUER_ID>',
  payer: {
    email: '<BUYER_EMAIL>',
  },
  three_d_secure_mode: 'optional'
}
payment.create({ body: body, requestOptions: { idempotencyKey: '<SOME_UNIQUE_VALUE>' } }).then(console.log).catch(console.log);

        
          
require 'mercadopago'
sdk = Mercadopago::SDK.new('<ENV_ACCESS_TOKEN>')
payment_request = {
  token: '<CARD_TOKEN>',
  installments: <INSTALLLMENTS_NUMBER>,
  transaction_amount: <TRANSACTION_AMOUNT>,
  description: '<DESCRIPTION>',
  payer: {
    email: '<BUYER_EMAIL>',
  },
  three_d_secure_mode: 'optional'
}
payment_response = sdk.payment.create(payment_request)
payment = payment_response[:response]

        
          
import mercadopago
sdk = mercadopago.SDK("<ENV_ACCESS_TOKEN>")
payment_data = {
    "transaction_amount": <TRANSACTION_AMOUNT>,
    "token": "<CARD_TOKEN>",
    "description": "<DESCRIPTION>",
    "installments": <INSTALLLMENTS_NUMBER>,
    "payer": {
        "email": "<BUYER_EMAIL>",
    },
    "three_d_secure_mode": "optional"
}
payment_response = sdk.payment().create(payment_data)
payment = payment_response["response"]

        
          
package main

import (
	"context"
	"fmt"

	"github.com/mercadopago/sdk-go/pkg/config"
	"github.com/mercadopago/sdk-go/pkg/payment"
)

func main() {
	accessToken := "<ENV_ACCESS_TOKEN>"

	cfg, err := config.New(accessToken)
	if err != nil {
		fmt.Println(err)
		return
	}

	client := payment.NewClient(cfg)

	request := payment.Request{
		TransactionAmount:<TRANSACTION_AMOUNT>,
		Payer: &payment.PayerRequest{
			Email: "<BUYER_EMAIL>",
		},
		Token:        "<CARD_TOKEN>",
		Installments: <INSTALLLMENTS_NUMBER>,
		Description: "<DESCRIPTION>",
		ThreeDSecureMode: "optional",
	}

	resource, err := client.Create(context.Background(), request)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(resource)
}

        
          
curl --location --request POST 'https://api.mercadopago.com/v1/payments' \
--header 'Authorization: <ENV_ACCESS_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "payer": {
        "email": "<BUYER_EMAIL>"
    },
    "additional_info": {
        "items": [
            {
                "quantity": <ITEM_QUANTITY>,
                "category_id": <CATEGORY_ID>,
                "title": <ITEM_TITLE>,
                "unit_price": <TRANSACTION_AMOUNT>
            }
        ]
    },
    "payment_method_id": <PAYMENT_METHOD_ID>,
    "marketplace": "NONE",
    "installments": <INSTALLLMENTS_NUMBER>,
    "transaction_amount": <TRANSACTION_AMOUNT>,
    "description": "<DESCRIPTION>",
    "token": "CARD_TOKEN",
    "three_d_secure_mode": "optional",
    "capture": true,
    "binary_mode": false
}'

        

Caso não seja necessårio utilizar o fluxo do Challenge, o campo de status do pagamento terå valor approved e não serå necessårio exibi-lo, dessa forma, siga normalmente com o fluxo de sua aplicação.

Para os casos em que o Challenge Ă© necessĂĄrio, o status mostrarĂĄ o valor pending, e o status_detail serĂĄ pending_challenge.

Importante
Neste Ășltimo caso, a resposta mostrarĂĄ um atributo de pagamento chamado three_ds_info com os campos external_resource_url, que contĂ©m a URL do Challenge, e creq, um identificador da solicitação do Challenge. Para exibi-lo e tratar seu resultado siga os passos abaixo.

Visão geral da resposta (informação omitida)

Quando o Challenge é iniciado, o usuårio tem cerca de 5 minutos para completå-lo. Se não for concluído, o banco recusarå a transação e o Mercado Pago considerarå o pagamento cancelado. Enquanto o usuårio não completar o Challenge, o pagamento ficarå como pending_challenge.

          
{
    "id": 52044997115,
    ...
    "status": "pending",
    "status_detail": "pending_challenge",
    ...
    "three_ds_info":
    {
        "external_resource_url": "https://acs-public.tp.mastercard.com/api/v1/browser_Challenges",
        "creq": "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImJmYTVhZjI0LTliMzAtNGY1Yi05MzQwLWJkZTc1ZjExMGM1MCIsImFjc1RyYW5zSUQiOiI3MDAwYTI2YS1jYWQ1LTQ2NjQtOTM0OC01YmRlZjUwM2JlOWYiLCJjaGFsbGVuZ2VXaW5kb3dTaXplIjoiMDQiLCJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIn0"
    },
    "owner": null
}


        
  1. Para uma melhor visualização do Challenge do 3DS de forma responsiva, vocĂȘ deve adicionar o CSS abaixo.

css

  #myframe{
    width: 500px;
    height: 600px;
    border: none;
  }
  @media only screen and (width <= 980px) {
    #myframe{
      width: 100%;
      height: 440px;
    }
  }
  1. Para exibir o Challenge, é necessårio gerar um iframe que contenha um formulårio com method post, action contendo a URL obtida no campo external_resource_url, e um input oculto com o valor obtido em creq. Em seguida, faça o post do formulårio abaixo para iniciar o Challenge.
          
function doChallenge(payment) {
  try {
    const {
      status,
      status_detail,
      three_ds_info: { creq, external_resource_url },
    } = payment;
    if (status === "pending" && status_detail === "pending_challenge") {
      var iframe = document.createElement("iframe");
      iframe.name = "myframe";
      iframe.id = "myframe";
      document.body.appendChild(iframe);

      var idocument = iframe.contentWindow.document;

      var myform = idocument.createElement("form");
      myform.name = "myform";
      myform.setAttribute("target", "myframe");
      myform.setAttribute("method", "post");
      myform.setAttribute("action", external_resource_url);

      var hiddenField = idocument.createElement("input");
      hiddenField.setAttribute("type", "hidden");
      hiddenField.setAttribute("name", "creq");
      hiddenField.setAttribute("value", creq);
      myform.appendChild(hiddenField);
      iframe.appendChild(myform);

      myform.submit();
    }
  } catch (error) {
    console.log(error);
    alert("Error doing Challenge, try again later.");
  }
}


        

Quando o Challenge for concluído, o status do pagamento serå atualizado para approved se a autenticação for bem-sucedida, e rejected se não for. Em situaçÔes nas quais a autenticação não é realizada, o pagamento permanece pending. Esta atualização não é imediata e pode levar alguns instantes.

Consulte a seção abaixo para obter mais detalhes sobre como verificar o status de cada transação.

Verificar status da transação

Para saber qual Ă© o resultado de cada transação, existem trĂȘs opçÔes:

  • NotificaçÔes: Uma notificação da alteração do status do pagamento serĂĄ recebida por meio de Webhooks e o comprador deverĂĄ ser redirecionado para uma tela indicando que a transação foi bem-sucedida. Consulte a seção Webhooks e saiba como realizar sua configuração..
  • API de pagamentos: SerĂĄ necessĂĄrio fazer um pooling em Payments e, se o status mudar, redirecionar o comprador para uma tela de confirmação.
  • Tratar o evento iframe (recomendado): Tenha em mente que o evento apenas indica que o Challenge terminou e nĂŁo que o pagamento chegou a um status final, pois a atualização nĂŁo Ă© imediata e pode demorar alguns instantes. Faça uma consulta em Payments e, caso o status mude, redirecione o comprador para uma tela indicando que a transação foi realizada com sucesso.

Para tratar o evento iframe, siga as etapas abaixo.

Realizar implantação

Utilize o código Javascript a seguir para implementar e escutar o evento que indica que o Challenge foi encerrado, assim é possível redirecionar o cliente para a tela de confirmação.

          
window.addEventListener("message", (e) => {
     if (e.data.status === "COMPLETE") {
         window.open("congrats.html");
     }
});


        

Buscar status de pagamento

O Javascript a seguir indica como buscar o status do pagamento atualizado e exibi-lo na tela de confirmação.

          
document.addEventListener("DOMContentLoaded", async function (e) {
 init();
});

async function init() {
 const id = localStorage.getItem("paymentId");

 try {
   const response = await fetch("/get_payment/" + id, {
     method: "GET",
   });
   const result = await response.json();
   if (result.status != 200) throw new Error("error getting payment");
   document.getElementById("congrats-div").innerHTML =
     "Pagamento " + result.data.id + " -> Status: " + result.data.status;
 } catch (error) {
   alert("Unexpected error\n" + JSON.stringify(error));
 }
}


        
Importante
Caso o pagamento ainda esteja pending após o timeout do Challenge, serå necessårio redirecionar o comprador para uma tela informando que o pagamento expirou e que é necessårio criar um novo (a atualização não é imediata, pode demorar alguns momentos).

Após seguir estes passos, sua integração estå pronta para autenticar transaçÔes com 3DS.

PossĂ­veis status de pagamento

Uma transação com 3DS pode retornar diferentes status dependendo do tipo de autenticação realizada (com ou sem Challenge).

Em um pagamento sem Challenge, o status da transação serå diretamente approved ou rejected. Enquanto que em um pagamento com Challenge, a transação ficarå com status pending e o processo de autenticação junto ao banco serå iniciado. Somente após esta etapa o status final serå exibido.

Veja abaixo a tabela com os possíveis status e suas respectivas descriçÔes.

StatusStatus_detailDescrição
"approved""accredited"Transação aprovada sem autenticação.
"rejected"-Transação rejeitada sem autenticação. Para conferir os motivos, consulte a lista padrão de status detail.
"pending""pending_challenge"Transação pendente de autenticação ou timeout do Challenge.
"rejected""cc_rejected_3ds_challenge"Transação rejeitada devido a falha no Challenge.
"cancelled""expired"Transação com Challenge cancelada após 24h no status pending.

Teste de integração

Para que seja possível validar pagamentos com 3DS, disponibilizamos um ambiente de testes do tipo sandbox que retorna resultados falsos apenas para simulação e validação da implementação.

Importante
Para testar a integração é necessårio utilizar suas credenciais de teste. Certifique-se também de incluir o atributo three_d_secure_mode, definindo-o como optional para garantir a correta implementação do pagamento 3DS.

Para realizar testes de pagamento em um ambiente sandbox, é necessårio utilizar cartÔes específicos que permitem testar a implementação do Challenge com os fluxos de sucesso e falha. A tabela a seguir apresenta os detalhes desses cartÔes:

CartĂŁoFluxoNĂșmeroCĂłdigo de segurançaData de vencimento
MastercardChallenge com sucesso5483 9281 6457 462312311/25
MastercardChallenge nĂŁo autorizado5361 9568 0611 755712311/25

Os passos para criar o pagamento sĂŁo os mesmos. Em caso de dĂșvida sobre como criar pagamentos com cartĂŁo, consulte a documentação sobre CartĂ”es.

          
<?php
  use MercadoPago\Client\Payment\PaymentClient;
  use MercadoPago\MercadoPagoConfig;
  MercadoPagoConfig::setAccessToken("YOUR_ACCESS_TOKEN");

  $client = new PaymentClient();
  $request_options = new RequestOptions();
  $request_options->setCustomHeaders(["X-Idempotency-Key: <SOME_UNIQUE_VALUE>"]);

  $payment = $client->create([
    "transaction_amount" => (float) $_POST['transactionAmount'],
    "token" => $_POST['token'],
    "description" => $_POST['description'],
    "installments" => $_POST['installments'],
    "payment_method_id" => $_POST['paymentMethodId'],
    "issuer_id" => $_POST['issuer'],
    "payer" => [
      "email" => $_POST['email'],
      "identification" => [
        "type" => $_POST['identificationType'],
        "number" => $_POST['number']
      ]
    ],
    "three_d_secure_mode" => "optional"
  ], $request_options);
  echo implode($payment);
?>

        
          
import { MercadoPagoConfig, Payment } from 'mercadopago';

const client = new MercadoPagoConfig({ accessToken: 'YOUR_ACCESS_TOKEN' });
const payment = new Payment(client);

const body = {
transaction_amount: req.transaction_amount,
  token: req.token,
  description: req.description,
  installments: req.installments,
  payment_method_id: req.paymentMethodId,
  issuer_id: req.issuer,
  payer: {
    email: req.email,
    identification: {
      type: req.identificationType,
      number: req.number
    }
  },
  three_d_secure_mode: 'optional' 
};

payment.create({ body: body, requestOptions: { idempotencyKey: '<SOME_UNIQUE_VALUE>' } }).then(console.log).catch(console.log);

        
          
PaymentClient client = new PaymentClient();

PaymentCreateRequest paymentCreateRequest =
   PaymentCreateRequest.builder()
       .transactionAmount(request.getTransactionAmount())
       .token(request.getToken())
       .description(request.getDescription())
       .installments(request.getInstallments())
       .paymentMethodId(request.getPaymentMethodId())
       .payer(
           PaymentPayerRequest.builder()
               .email(request.getPayer().getEmail())
               .firstName(request.getPayer().getFirstName())
               .identification(
                   IdentificationRequest.builder()
                       .type(request.getPayer().getIdentification().getType())
                       .number(request.getPayer().getIdentification().getNumber())
                       .build())
               .build())
       .threeDSecureMode("optional")
       .build();

client.create(paymentCreateRequest);

        
          
require 'mercadopago'
sdk = Mercadopago::SDK.new('YOUR_ACCESS_TOKEN')
 
payment_data = {
 transaction_amount: params[:transactionAmount].to_f,
 token: params[:token],
 description: params[:description],
 installments: params[:installments].to_i,
 payment_method_id: params[:paymentMethodId],
 payer: {
   email: params[:email],
   identification: {
     type: params[:identificationType],
     number: params[:identificationNumber]
   }
 three_d_secure_mode: "optional",
 }
}
 
payment_response = sdk.payment.create(payment_data)
payment = payment_response[:response]
 
puts payment

        
          
using System;
using MercadoPago.Client.Common;
using MercadoPago.Client.Payment;
using MercadoPago.Config;
using MercadoPago.Resource.Payment;
 
MercadoPagoConfig.AccessToken = "YOUR_ACCESS_TOKEN";
 
var paymentRequest = new PaymentCreateRequest
{
   TransactionAmount = decimal.Parse(Request["transactionAmount"]),
   Token = Request["token"],
   Description = Request["description"],
   Installments = int.Parse(Request["installments"]),
   PaymentMethodId = Request["paymentMethodId"],
   Payer = new PaymentPayerRequest
   {
       Email = Request["email"],
       Identification = new IdentificationRequest
       {
           Type = Request["identificationType"],
           Number = Request["identificationNumber"],
       },
   },
ThreeDSecureMode = "optional",
};
 
var client = new PaymentClient();
Payment payment = await client.CreateAsync(paymentRequest);
 
Console.WriteLine(payment.Status);

        
          
import mercadopago
sdk = mercadopago.SDK("ACCESS_TOKEN")
 
payment_data = {
   "transaction_amount": float(request.POST.get("transaction_amount")),
   "token": request.POST.get("token"),
   "description": request.POST.get("description"),
   "installments": int(request.POST.get("installments")),
   "payment_method_id": request.POST.get("payment_method_id"),
   "payer": {
       "email": request.POST.get("email"),
       "identification": {
           "type": request.POST.get("type"), 
           "number": request.POST.get("number")
       }
   }
   "three_d_secure_mode": "optional"
}
 
payment_response = sdk.payment().create(payment_data)
payment = payment_response["response"]
 
print(payment)

        
          
package main

import (
	"context"
	"fmt"

	"github.com/mercadopago/sdk-go/pkg/config"
	"github.com/mercadopago/sdk-go/pkg/payment"
)

func processPayment(r *http.Request) {
	accessToken := "{{ACCESS_TOKEN}}"

	cfg, err := config.New(accessToken)
	if err != nil {
		fmt.Println(err)
		return
	}

	client := payment.NewClient(cfg)

	request := payment.Request{
		TransactionAmount: r.FormValue("transactionAmount"),
		Token: r.FormValue("token"),
            Description: r.FormValue("description"),
		PaymentMethodID:   r.FormValue("paymentMethodId"),
		Payer: &payment.PayerRequest{
			Email: r.FormValue("email"),
			Identification: &payment.IdentificationRequest{
				Type: r.FormValue("type"),
				Number: r.FormValue("number"),
			},
		},
	}

	resource, err := client.Create(context.Background(), request)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(resource)
}

        
          
curl -X POST \
   -H 'accept: application/json' \
   -H 'content-type: application/json' \
   -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
   'https://api.mercadopago.com/v1/payments' \
   -d '{
         "transaction_amount": 100,
         "token": "CARD_TOKEN",
         "description": "Blue shirt",
         "installments": 1,
         "payment_method_id": "master",
         "issuer_id": 310,
         "payer": {
           "email": "PAYER_EMAIL"
         },
         "three_d_secure_mode": "optional"
   }'

        

Challenge

Em ambos os fluxos (sucesso e falha), o Challenge, que Ă© uma tela semelhante Ă  mostrada abaixo, deve ser exibido dentro do iframe:

Challenge

O código de verificação fornecido é apenas ilustrativo. Para concluir o fluxo de teste, basta clicar no botão Confirmar. Após concluir essa ação, siga as instruçÔes detalhadas na seção Verificar status da transação para identificar quando o Challenge foi concluído e como verificar a atualização do pagamento.