Com a configuração pronta, o fluxo de uma transação utilizando 3D Secure 2 na Malga envolve várias etapas. Abaixo descrevemos cada passo com explicações e exemplos práticos:

Passo 1: Setup da Sessão 3DS2

Antes de criar uma cobrança (transação) com 3DS2, é necessário iniciar uma sessão de autenticação. Essa etapa de setup prepara o provedor de autenticação 3DS e retorna parâmetros que serão usados nas próximas etapas. Você deve chamar o endpoint /v1/charges/3ds/setup informando a fonte do cartão. Essa fonte pode ser um cartão tokenizado (sourceType: "token") ou um cartão previamente cadastrado (sourceType: "card"), junto com o identificador correspondente (tokenId ou cardId). Exemplo de requisição (Setup 3DS2):
curl --request POST 'https://api.malga.io/v1/charges/3ds/setup' \
--header 'x-api-key: <SEU_API_KEY>' \
--header 'x-client-id: <SEU_CLIENT_ID>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "sourceType": "token",
    "tokenId": "123e4567-e89b-12d3-a456-426614174000"
}'
No primeiro exemplo acima, foi utilizado um cartão tokenizado (substitua “tokenId” por um ID de token de cartão válido obtido via tokenização da Malga). Se você tivesse um cardId, poderia usá-lo alterando sourceType para card. Resposta do Setup: Ao chamar o setup, a API retorna um objeto contendo informações essenciais para prosseguir. Um exemplo simplificado de resposta JSON seria:
{
  "id": "11111111-2222-3333-4444-555555555555",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....", 
  "collectUrl": "https://centinel.api.cardecommerce.com/V1/Cruise/Collect",
  "providerType": "CYBERSOURCE",
  "error": null
}
Os campos importantes desse retorno são:
  • id – Identificador único da sessão 3DS2 criada. Este Setup ID será usado posteriormente ao criar a cobrança 3DS2.
  • token – Um token JWT fornecido pelo provedor de autenticação 3DS. Este token deverá ser usado na próxima etapa de coleta de dados no navegador do cliente.
  • collectUrl – URL para a qual os dados do dispositivo do cliente deverão ser enviados. Também será usada na etapa de coleta de dados no front-end.
  • providerType – Indica qual provedor de 3DS2 está sendo utilizado (ex: CYBERSOURCE, etc).
  • error – Em caso de falha na criação da sessão, este campo trará detalhes do erro; caso contrário virá como null.
Guarde o valor de id retornado (Setup ID), pois ele será necessário no passo de criação da cobrança. Em seguida, prossiga imediatamente para a etapa de coleta de dados do dispositivo no navegador.

Passo 2: Coleta de Dados do Dispositivo (Data Collection)

Com o token e o collectUrl retornados no setup, é preciso coletar informações do dispositivo/navegador do comprador. Essa coleta é feita no front-end do seu checkout, normalmente via um formulário invisível e um iframe, e serve para o provedor 3DS reunir dados de contexto para a autenticação. Para implementar essa etapa, inclua no HTML do seu checkout um bloco de código semelhante ao abaixo:
<!-- Elementos ocultos para coleta de dados 3DS2 -->
<div style="display: none;">
  <iframe id="collection_iframe" name="collectionIframe" height="1" width="1"></iframe>
  <form id="collection_form" method="POST" target="collectionIframe">
    <input id="collection_input" type="hidden" name="JWT" value="" />
  </form>
</div>
<script>
  // Valores obtidos na resposta do setup:
  const collectUrl = "<URL_RETORNADA_NO_SETUP>";   // ex: https://centinel.api.../Collect
  const token3DS = "<TOKEN_RETORNADO_NO_SETUP>";   // JWT retornado no setup
  
  // Configura o formulário oculto com os dados de coleta:
  const form = document.getElementById('collection_form');
  const input = document.getElementById('collection_input');
  form.action = collectUrl;
  input.value = token3DS;
  form.submit();

  // Listener para detectar conclusão da coleta
  window.addEventListener("message", function(event) {
    const expectedOrigin = new URL(collectUrl).origin;
    if (event.origin === expectedOrigin) {
      console.log("Coleta de dados 3DS2 finalizada:", event.data);
      // Você pode opcionalmente enviar um evento ou atualizar o estado do checkout aqui
    }
  });
</script>
No código acima, substitua collectUrl e token3DS pelos valores reais obtidos no Passo 1. Ao executar esse script, o formulário é enviado em background (iframe oculto) para a URL de coleta do provedor 3DS, junto com o token JWT. O provedor então coleta atributos do navegador (como informações de dispositivo, IP, etc.) automaticamente. Um event listener é adicionado para ouvir a mensagem de retorno indicando que a coleta terminou (o provedor geralmente envia um evento de mensagem para a janela original ao concluir a coleta). Essa etapa é fundamental para a autenticação 3DS: ela fornece ao emissor do cartão os dados contextuais do dispositivo do cliente, auxiliando na decisão de aprovar diretamente (autenticação frictionless) ou exigir um desafio.

Passo 3: Criação da Cobrança (Transação com 3DS2)

Com a sessão criada (Setup ID) e a coleta de dados realizada, você pode prosseguir para criar a cobrança (transação de pagamento). A requisição de cobrança é feita no endpoint padrão /v1/charges, porém deve conter um objeto adicional threeDSecure2 com os campos necessários. Na cobrança 3DS2, o provedor de pagamento tentará autenticar o portador do cartão junto ao banco emissor. Dependendo do resultado, o pagamento poderá ser autenticado de forma silenciosa (frictionless) ou o emissor pode solicitar um desafio adicional ao cliente (challenge). Montar a requisição corretamente é crucial. Segue um exemplo de requisição cURL para criar uma cobrança com 3DS2:
curl --request POST 'https://api.malga.io/v1/charges' \
  --header 'x-api-key: <SEU_API_KEY>' \
  --header 'x-client-id: <SEU_CLIENT_ID>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "merchantId": "<MERCHANT_ID>",
    "amount": 5790,
    "currency": "BRL",
    "capture": true,
    "statementDescriptor": "Compra 3DS2 - Pedido 12345",
    "paymentSource": {
      "sourceType": "token",
      "tokenId": "123e4567-e89b-12d3-a456-426614174000"
    },
    "paymentMethod": {
      "paymentType": "credit",
      "installments": 1
    },
    "paymentFlow": {
      "metadata": {
        "exemplo": "algum valor"
      }
    },
    "threeDSecure2": {
      "requiresLiabilityShift": true,
      "setupId": "<ID_RETORNADO_NO_SETUP>",
      "redirectURL": "https://www.sualoja.com.br/checkout",
      "requestorURL": "https://www.sualoja.com.br",
      "billingAddress": {
        "city": "São Paulo",
        "country": "BR",
        "street": "Avenida Exemplo",
        "streetNumber": "100",
        "zipCode": "01010010",
        "state": "SP"
      },
      "browser": {
        "ip": "203.0.113.45",
        "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
        "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "language": "pt-BR",
        "colorDepth": 24,
        "screenHeight": 1080,
        "screenWidth": 1920,
        "timeZoneOffset": "180",
        "javaEnabled": false,
        "javaScriptEnabled": true
      },
      "cardHolder": {
        "email": "cliente@example.com",
        "mobilePhone": "5511999999999"
      }
    }
  }'
Vamos explicar os principais campos usados acima dentro de threeDSecure2::
requiresLiabilityShift
boolean
Indica se você exige o liability shift. Se true, a transação só prosseguirá se houver mudança de responsabilidade para o emissor.
setupId
string
required
O ID da sessão de setup obtido no Passo 1. Obrigatório; vincula a transação atual com os dados coletados anteriormente.
redirectURL
string
A URL para a qual o cliente será redirecionado de volta após completar a autenticação 3DS (no caso de desafio). Normalmente é uma página do seu site (por exemplo, a página de confirmação de pedido ou de checkout) que irá processar a resposta. O provedor/autenticador usará esta URL para retornar o controle ao seu sistema após o desafio.
requestorURL
string
URL do domínio do lojista (merchant), geralmente o endereço do seu site. Esse valor pode ser usado internamente pelo provedor 3DS2 durante a autenticação para verificar a origem da requisição.
billingAddress
object
Endereço de cobrança do portador do cartão. Campos como cidade, país, CEP, etc. (Dados importantes para análise de risco e autenticação).
browser
object
required
Objeto contendo informações do navegador do comprador, coletadas preferencialmente do próprio navegador do cliente. Inclua exatamente os dados requeridos:
  • ip: IP do cliente.
  • userAgent: String do agente de usuário do navegador.
  • acceptHeader: Conteúdo do header HTTP “Accept” enviado pelo browser.
  • language: Idioma preferido do navegador (por exemplo, “pt-BR”).
  • colorDepth, screenHeight, screenWidth: Profundidade de cor e resolução de tela do dispositivo.
  • timeZoneOffset: Fuso horário do usuário em minutos (ex.: Brasil = “180” minutos atrasados em relação a UTC).
  • javaEnabled: Se Java (Applet) está habilitado no browser (geralmente false hoje em dia).
  • javaScriptEnabled: Se o navegador tem JavaScript habilitado (true na maioria dos casos).
cardHolder
object
Informações do portador do cartão, como email e telefone celular. Esses dados podem ser utilizados pelo emissor durante a autenticação (por exemplo, enviar um OTP via SMS).
Observação: No exemplo acima, usamos valores simulados (como IP e userAgent abreviado). Em um cenário real, você deve capturar esses dados do navegador do cliente no front-end e passá-los corretamente na requisição. A Malga não coleta esses dados automaticamente, portanto sua aplicação cliente deve fornecê-los (por exemplo, usando window.navigator para obter userAgent, screen.width etc., e APIs do browser para IP se disponível, ou obtendo IP do lado servidor).
Resposta da Cobrança: Ao criar a cobrança com 3DS2, a resposta da API incluirá, além dos dados da transação, um objeto threeDSecure2.authData com informações sobre a autenticação. Em particular, duas situações podem ocorrer:
  • Transação Autorizada de imediato (Frictionless): O campo status da transação vem como authorized ou pre_authorized indicando que o banco emissor não exigiu desafio.
{
    ...
    "threeDSecure2": {
        "authData": {
            "action": "REDIRECT",
            "networkTransactionId": "7518984890596838804807",
            "providerType": "CYBERSOURCE",
            "response": null,
            "responseType": "AUTHORIZATION"
        },
        "authenticated": true
    }
}
  • Transação Pendente (Desafio necessário): O campo status da transação virá como pending, indicando que o emissor solicitou um desafio (challenge) de autenticação. Nesse caso, o objeto threeDSecure2.authData.response trará os campos stepUrl e token que serão usados para iniciar o desafio. A transação ficará pendente até a conclusão do desafio pelo cliente.
{
  ...
  "threeDSecure2": {
        "authData": {
            "action": "REDIRECT",
            "networkTransactionId": "7518912480166601504805",
            "providerType": "CYBERSOURCE",
            "response": {
                "pareq": "...",
                "stepUrl": "https://centinelapistag.cardinalcommerce.com/V2/Cruise/StepUp",
                "token": "..."
            },
            "responseType": "AUTHENTICATION"
        },
        "authenticated": null
  }
}
No caso pending, prossiga para o Passo 4 abaixo para realizar o desafio de autenticação. Se a transação foi autorizada sem desafio, você pode pular o próximo passo e apenas informar o cliente do resultado (ou confirmar pagamento, etc.).

Passo 4: Desafio de Autenticação (Challenge 3DS2)

Quando o banco emissor exige uma validação adicional, é preciso apresentar ao cliente o desafio 3DS - normalmente uma tela onde ele deve, por exemplo, inserir um código SMS, senha ou outro fator de autenticação. A Malga simplifica esse processo fornecendo a URL e o token necessários para abrir a interface do banco emissor em um iframe dentro do seu site (ou via redirecionamento). Assim como na coleta de dados, a implementação do desafio é feita no front-end, inserindo um formulário que será automaticamente enviado para o stepUrl do desafio, contendo o token de autorização. Esses valores foram retornados na resposta da cobrança (Passo 3) dentro de threeDSecure2.authData.response.stepUrl e ...response.token. Você pode implementar de forma similar à abaixo no seu HTML (por exemplo, abrindo um modal ou sobreposição com um iframe para o desafio):
<!-- Elementos para o desafio 3DS2 (exibidos ao usuário) -->
<div id="desafio_3ds" style="display: none;">
  <!-- Formulário que será submetido ao banco emissor -->
  <form id="step_form" method="POST" target="stepUpIframe">
    <input id="step_input_jwt" type="hidden" name="JWT" value="" />
  </form>
  <!-- Iframe para exibir o conteúdo do desafio do emissor -->
  <iframe id="stepUpIframe" name="stepUpIframe" style="border:none; width:400px; height:800px;"></iframe>
</div>
<script>
  // Valores obtidos da resposta da cobrança 3DS (authData):
  const stepUrl = "<URL_RETORNADA_NO_AUTHDATA>";   // e.g., https://acs.cardissuer.com/step-auth
  const stepToken = "<TOKEN_RETORNADO_NO_AUTHDATA>"; // JWT do authData para desafio

  // Submete o formulário de desafio:
  const formStep = document.getElementById('step_form');
  const inputJwt = document.getElementById('step_input_jwt');
  formStep.action = stepUrl;
  inputJwt.value = stepToken;
  formStep.submit();
  
  // Exibe o iframe/modal de desafio para o usuário
  document.getElementById('desafio_3ds').style.display = 'block';
</script>
No código acima, stepUrl (threeDSecure2.authData.response.stepUrl) e stepToken (threeDSecure2.authData.response.token) devem ser preenchidos com os valores retornados na resposta da criação da cobrança pendente (obtidos no Passo 3). Ao executar formStep.submit(), o navegador irá redirecionar o iframe para o endereço do desafio do emissor, efetivamente carregando a página de autenticação do banco dentro do iframe. O cliente então interage com essa página (por exemplo, digitando a senha do cartão ou um código enviado por SMS). Durante o desafio, o navegador do cliente está se comunicando diretamente com o banco emissor (via provedor 3DS). Uma vez concluído (sucesso, falha ou expirado), o fluxo de 3DS2 providenciará um redirecionamento de volta para a URL que você configurou em redirectURL no Passo 3.

Passo 5: Verificando o Resultado Final

Após o cliente completar (ou tentar) o desafio e retornar para o seu site (URL de retorno configurada), é necessário verificar o status final da transação para saber se o pagamento foi autorizado ou negado pelo emissor. A Malga permite consultar a transação a qualquer momento via API, então você deve fazer uma requisição GET para o endpoint /v1/charges/{chargeId} usando o ID da cobrança criada no Passo 3. Por exemplo, suponha que o ID da cobrança retornado no Passo 3 foi 6607c9b8-f6a3-48e2-9918-518d41d2fa60. Você pode consultá-la assim:
curl --request GET 'https://api.malga.io/v1/charges/6607c9b8-f6a3-48e2-9918-518d41d2fa60' \
  --header 'x-api-key: <SEU_API_KEY>' \
  --header 'x-client-id: <SEU_CLIENT_ID>' \
  --header 'Accept: application/json'
A resposta trará todos os detalhes da cobrança, incluindo o campo status atualizado (que após o desafio provavelmente estará como authorized se o cliente autenticou com sucesso e o pagamento foi aprovado, ou outro status final como declined em caso de falha). Você também poderá ver dentro de threeDSecure2 detalhes como authenticated: true/false, liabilityShift: true/false, etc., indicando o resultado da autenticação 3DS2.