Payment Vault

Esta página documenta detalles para integrar las el Payment Vault DEUNA en tu aplicación.

Elige tu integración

Almacena y tokeniza credenciales de pago con el Vault DEUNA.

Integra el Vault a tu solución de pagos mediante las sigientes opciones:

Vault via SDK (recomendado)

Recomendamos integrar el Payment Vault mediante nuestros SDKs, ya que ofrecen una experiencia más optimizada y simplifican la comunicación entre las aplicaciones y las páginas web. A continuación, se listan los SDKs disponibles:

📘

En entornos web, el widget puede abrirse en un elemento HTML objetivo o mostrarse como un modal.

📘

En aplicaciones móviles (iOS y Android), el widget se abre dentro de un WebView.

Funcionalidades

El SDK expone varios callbacks que permiten al comercio reaccionar de forma dinámica ante eventos importantes dentro del flujo de pago, como:

  • Cuando el usuario cierra el widget.
  • Cuando se tokeniza exitosamente una tarjeta o credencial de pago.
  • Cuando falla un intento de tokenización.

Estas funcionalidades permiten al comercio personalizar la experiencia del usuario y adaptarla según las necesidades de cada transacción.

Vault via URL / iFrame

Puedes renderizar el Payment Widget dentro de un Iframe o en un tab completo como redirect, en caso de que no puedas usar los SDKs.

📘

Para integrar el Payment Vaultpor URL o iFrame, ve a Vault via URL / iFrame.

Información adicional

Conoce más acerca de la integración del Payment Vault:

  • Verificación del tipo de evento y marca de la tarjeta: El Vault reconoce la marca de tarjetas a partir de metadata de eventos.
  • Aplicación de descuento si la tarjeta es Mastercard por el comercio: Si la marca de la tarjeta es 'mastercard', se aplica un descuento del 20% al carrito de compras actual. Esta acción es realizada 100% por tu aplicación.
  • Actualización de la orden: Después de aplicar un descuento, tu aplicación es responsable de actualizar la orden utilizando el endpoint Actualizar Orden de DEUNA.
  • Notificación al widget para actualizar la orden e installments: Los cambios de estatus de una orden se comunican mediante el método postMessage.
    • El método postMessage envía un mensaje al widget indicando que pasos a seguir dependiendo de la lógica de negocio.
    • Se debe incluir un objeto con el tipo 'refetchOrder' y con un valor de data igual a null.
  • Mostrar un tag promocional: Además de actualizar la orden y las cuotas de pago, es posible aplicar un estilo CSS personalizado mediante la función getCustomCSS(cardBrand) al widget.

Procesar un pago con un card_id o credential de pago

Cuando un proceso de pago se inicia en el backend de tu aplicación, debes configurar el pago con un card_id para finalizar la compra.

📘

Debes integrar los endpoints de Pagos para obtener los card_id.

Este proceso requiere solicitudes específicas al endpoint de la API de Pagos para concluir la transacción.

Ejemplo de solicitud curl

const requestBody = {
    payer_info: {
        email: "[email protected]"
    },
    payment_source: {
        method_type: "credit_card",
        card_info: {
            card_id: "8d369b6e-113a-4640-9e63-dc29957fc86aza",
            installment: {
            	plan_option_id: "<uuid que se retorna en el postMessage 'onInstallmentSelected'>"
            }
        }
    },
    // ... 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-staging.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();
    }
}

👍

Ver el API reference

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

Demo de experiencia

Después de integrar el Payment Vault la experiencia es similar al siguiente demo:


Continua leyendo