Integración paso a paso

Paso 1: Selecciona el tipo y método de integración

Tipos de integración:

  1. Vault Widget: este widget le permite al cliente agregar o seleccionar una tarjeta existente en el ecosistema Click to Pay. Este widget lo único que hace es obtener la tarjeta seleccionada por el cliente en Click to Pay y retornarla para que el comercio pueda usarla para generar un pago vía API por DEUNA.
  2. Payment Widget: este widget le permite al cliente agregar o seleccionar una tarjeta existe en el ecosistema de Click to Pay y usarla para procesar el pago. A diferencia de la funcionalidad del Vault Widget este widget también es responsable de procesar el pago.

    📘

    If you will be using Click to Pay using the Payment Widget, make sure that the parent website where you are embedding the Payment Widget uses HTTPS. This is a security requirement from Click to Pay.

Métodos de integración:

  1. Vault Widget:
    1. Web SDK (coming soon 🔜)
    2. iOS SDK
    3. Android SDK
    4. Integración vía URL (no recomendada)
  2. Payment Widget:
    1. Web SDK
    2. iOS SDK
    3. Android SDK

Paso 2: Configuración del componente


Primero, activa desde nuestro admin e integra el componente de Click to Pay en tu aplicación. Esto implica configurar un iframe con una URL específica que proporcionamos, que debe incluir parámetros esenciales como la clave API pública y datos del usuario.

Configuración en el ADMIN de DEUNA

  • Accede a admin.deuna.com, y activa Click to Pay

Inicializar un Iframe en tu aplicación con la URL de DEUNA

Utiliza la URL proporcionada por nosotros para el iframe. Asegúrate de incluir los parámetros requeridos para personalizar la experiencia del usuario

URL para integración

https://elements.sandbox.deuna.io/click_to_pay?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}
https://elements.deuna.com/click_to_pay?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}

Es esencial entender que como desarrollador, tu responsabilidad es integrar este componente dentro de un iframe en tu sitio web o webView para apps. Esta integración es vital para garantizar una experiencia de usuario segura y fluida.

Atributos permitidos en Query Params

AtributoDescripción
publicApiKey (requerido)La llave pública de tu cuenta con DEUNA.
firstName (requerido)El nombre del usuario que está siendo registrado o autenticado.
lastName (requerido)El apellido del usuario.
email (opcional)La dirección de correo electrónico del usuario. En caso no sea enviada a la integración,se mostrará una pantalla para recopilar el correo electrónico, ya que es un requisito de Click to Pay para iniciar su flujo."
cssFile (opcional)UUID proporcionado por DEUNA. Esto aplica si quieres configurar un archivo css personalizado.
userToken(optional)El bearer token del usuario de DEUNA. Cuando este es enviado, todas las acciones dentro del widget van a hacer sobre este usuario de DEUNA. Adicionalmente, cuando se envía este userToken, no es necesario mandar ni el email, firstName, lastName. Solo será requerido el userTokeny el publicApiKey

👍

Nota importante: Asegúrate de que los Query Params estén codificados adecuadamente en caso de que contengan caracteres especiales. Esto es fundamental para evitar posibles problemas en las solicitudes.

Manejo del Caso: Comercio No Envía el Correo Electrónico

En ciertos casos, el comercio puede no enviar la dirección de correo del usuario en los parámetros de la consulta. Para resolver esta situación, DEUNA proporciona una vista específica que permite recopilar el correo del usuario, lo cual es necesario para iniciar el flujo de Click to Pay. A continuación, se detalla el flujo

Descripción del Flujo

  1. Pantalla de recolección de correo electrónico:
  • Si el correo electrónico no se proporciona a través de los Query Params, se presentará una vista diseñada para recopilar la dirección de correo del usuario.
  • Dicha pantalla es obligatoria, ya que Click to Pay requiere este dato para iniciar su flujo. Esta vista controla la validación del correo.
  1. Inicio del flujo en Click to Pay
  • Una vez recopilado, el correo electrónico se utilizará para iniciar el flujo en la plataforma de Click to Pay. Y seguir los steps de acuerdo al tipo de usuario en cuestión. Según el estado del usuario (Guest, Remembered o Registered), Click to Pay continuará con el flujo correspondiente para completar la transacción.

Consideraciones Importantes

  • Requerimiento obligatorio: La integración con Click to Pay no puede completarse sin un correo electrónico, por lo que esta pantalla es crítica para asegurar la continuidad del proceso.

De este modo garantizamos que el flujo de Click to Pay pueda ejecutarse incluso si el comercio no proporciona inicialmente el correo electrónico del usuario.

Script de Ejemplo

A continuación, te mostramos un ejemplo de cómo integrar esta URL en tu sitio web usando HTML, CSS y JavaScript:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Click to Pay Integration</title>
    <style>
      /* Estilos básicos para el iframe */
      #click-to-pay-iframe {
          width: 100%;
          height: 500px; /* Ajusta la altura según tus necesidades */
          border: none;
      }
    </style>
  </head>
  <body>
    <iframe
      id="click-to-pay-iframe"
      src="https://elements.sandbox.deuna.io/click_to_pay?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}"
      allow="payment"
    >
    </iframe>

    <script>
      // Escucha los mensajes de postMessage para recibir el card_id (a.k.a card token)
      window.addEventListener('message', function(event) {
          if (event.origin !== "https://elements.sandbox.deuna.io") {
              return;
          }
          let firstParsedData;
          if (typeof event.data === 'string') {
              firstParsedData = JSON.parse(event.data);
          } else {
              firstParsedData = event.data;
          }

          const parsedData = JSON.parse(firstParsedData);
          console.log('postMessage:', parsedData);

          if (
            parsedData &&
            parsedData.type === "vaultSaveSuccess"
        ) {
          // obtener el card_id (a.k.a card token)
          const cardId = parsedData.data.metadata.createdCard.id;

          // crear pago con el card_id
        }
      });
    </script>
  </body>
</html>

El componente de DEUNA se encargará del proceso de comunicación con Click to Pay, incluyendo el proceso de guardado de tarjeta. Una vez que este proceso sea exitoso, DEUNA enviará un evento mediante postMessage con el card_id válido. Este card_id es un elemento clave que debes enviar al realizar la llamada al endpoint de purchase desde tu backend para completar el pago.

Paso 2: Manejo de eventos con postMessage


Tras procesar una tarjeta con éxito en DEUNA, recibirás un evento postMessage con el card_id. Este card_id es esencial para procesar el pago final en tu backend.

window.addEventListener("message", (event) => {
  if (event.origin !== "URL_DE_CONFIANZA") { // Reemplaza con tu URL de confianza
    return;
  }

  switch (event.data.type) {
    case 'VaultStarted':
      // Click to Pay está listo
      break;

    case 'VaultSaveSuccess':
      // Tarjeta guardada con éxito, obtén el card_id
      const cardId = event.data.metadata.createdCard.id;
      // Usa card_id para procesar el pago
      break;

    case 'VaultSaveError':
    case 'VaultFailed':
      // Manejo de errores
      const errorCode = event.data.metadata.errorCode;
      const errorMessage = event.data.metadata.errorMessage;
      break;

    case 'VaultProcessing':
      // Pago en proceso
      break;

    // Añade más casos según sea necesario
  }
});

Utiliza este ejemplo como guía para configurar tu manejador de eventos y reacciona adecuadamente a cada tipo de mensaje.

Visita la sección Manejo de eventos con postMessage donde encontrarás información detallada sobre estos eventos, incluyendo descripciones completas y recomendaciones sobre cómo manejarlos efectivamente.

Paso 3: Proceso para finalizar el pago


Una vez que el proceso de pago se haya iniciado en tu aplicación mediante el backend, el siguiente paso crucial es integrar el endpoint para finalizar la compra. Este proceso implica configurar una solicitud específica al endpoint de la API para concluir la transacción. Por ejemplo, puedes utilizar una solicitud curl como se muestra a continuación:

Nota: El valor enviado en el atributo card_id es el que DEUNA envía mediante el método postMessage durante el evento VaultSavedSuccess.

const requestBody = {
    payer_info: {
        email: "[email protected]"
    },
    payment_source: {
        method_type: "credit_card",
        card_info: {
            card_id: "8d369b6e-113a-4640-9e63-dc29957fc86aza"
        }
    },
    // ... Resto del body
};

fetch('https://api.sandbox.deuna.io/v2/merchants/orders/purchase', {
    method: 'POST',
    headers: {
        'x-api-key': 'YOUR_PRIVATE_API_KEY',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(requestBody)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
curl --location 'https://api.sandbox.deuna.io/v2/merchants/orders/purchase' \
--header 'x-api-key: YOUR_PRIVATE_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
    "payer_info": {
        "email": "[email protected]"
    },
    "payment_source": {
        "method_type": "credit_card",
        "card_info": {
            "card_id": "8d369b6e-113a-4640-9e63-dc29957fc86aza"
        }
    },
    "order": {
        "order_id": "testapi-0003",
        "currency": "MXN",
        "items": [
          {
              "id": "216",
              "name": "10 Cellphones",
              "description": "",
              "options": "string option",
              "total_amount": {
                  "original_amount": 2000,
                  "amount": 2000,
                  "currency": "MXN",
                  "currency_symbol": "$"
              },
              "unit_price": {
                  "amount": 200,
                  "currency": "MXN",
                  "currency_symbol": "$"
              },
              "tax_amount": {
                  "amount": 0,
                  "currency": "MXN",
                  "currency_symbol": "$"
              },
              "quantity": 1,
              "uom": "string",
              "upc": "string",
              "sku": "",
              "isbn": "",
              "brand": "",
              "manufacturer": "",
              "category": "",
              "color": "",
              "size": "",
              "weight": {
                  "amount": 0,
                  "unit": "kg"
              },
              "image_url": "https://images-sandbox.getduna.com/95463fb5-6279-4ec3-8ff9-fe07aacd2142/db5b698c57654116_domicilio_216_750x750_1662162887.png?d=200x200&format=webp",
              "details_url": "",
              "type": "physcal",
              "taxable": true
          }
        ],
        "sub_total": 2000,
        "total_amount": 2000,
        "store_code": "all",
        "billing_address": {
            "address1": "presa angostura 36PH",
            "address2": "",
            "address_type": "home",
            "city": "CDMX",
            "country_code": "MX",
            "email": "[email protected]",
            "first_name": "efren",
            "identity_document": "162915134",
            "is_default": true,
            "last_name": "garcia",
            "phone": "+525222222222",
            "state_code": "MX",
            "state_name": "miguel hidalgo",
            "zipcode": "11500"
        }
    }
}'
$curl = curl_init();

$requestBody = json_encode(array(
    "payer_info" => array(
        "email" => "[email protected]"
    ),
    "payment_source" => array(
        "method_type" => "credit_card",
        "card_info" => array(
            "card_id" => "8d369b6e-113a-4640-9e63-dc29957fc86aza"
        )
    ),
    // Aquí puedes continuar añadiendo el resto del cuerpo de la solicitud
    "order" => array(
        "order_id" => "testapi-0003",
        "currency" => "MXN",
        "items" => array(
            // Aquí van los detalles de los items
        ),
        // Continúa con el resto de los detalles del pedido
    )
));

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://api.sandbox.deuna.io/v2/merchants/orders/purchase",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $requestBody, // Aquí se utiliza la variable
  CURLOPT_HTTPHEADER => array(
    "x-api-key: YOUR_PRIVATE_API_KEY", // Asegúrate de reemplazar con tu API key real
    "Content-Type: application/json"
  ),
));


$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
require 'uri'
require 'net/http'
require 'json'

url = URI("https://api.sandbox.deuna.io/v2/merchants/orders/purchase")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request_body = {
    payer_info: {
        email: "[email protected]"
    },
    payment_source: {
        method_type: "credit_card",
        card_info: {
            card_id: "8d369b6e-113a-4640-9e63-dc29957fc86aza"
        }
    }
    # ... Agrega aquí el resto del cuerpo de la solicitud
}.to_json

request = Net::HTTP::Post.new(url)
request["x-api-key"] = "YOUR_PRIVATE_API_KEY" # Reemplaza con tu API key
request["Content-Type"] = "application/json"
request.body = request_body

response = http.request(request)
puts response.read_body
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.json.JSONObject;

public class Main {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        
        JSONObject requestBody = new JSONObject()
            .put("payer_info", new JSONObject().put("email", "[email protected]"))
            .put("payment_source", new JSONObject()
                .put("method_type", "credit_card")
                .put("card_info", new JSONObject().put("card_id", "8d369b6e-113a-4640-9e63-dc29957fc86aza")))
            // ... Agrega aquí el resto del cuerpo de la solicitud

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.sandbox.deuna.io/v2/merchants/orders/purchase"))
            .header("x-api-key", "YOUR_PRIVATE_API_KEY") // Reemplaza con tu API key
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(requestBody.toString()))
            .build();

        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::body)
            .thenAccept(System.out::println)
            .join();
    }
}

👍

Nota Importante: Para revisar en detalle el endpoint te recomendamos ir a realizar pago de orden

Demo de experiencia


Felicidades, ya haz implementado click to pay. Ahora podrás ver una experiencia similar a la siguiente

Personalización de CSS en el componente (Opcional)


El componente te permite realizar personalizaciones en el formulario de tarjetas, para más información de configuración ir a la sección Personalización CSS de componentes

Prueba tu integración (Tarjetas de prueba)


Usa las tarjetas de prueba de Click to Pay descritas en el siguiente link