Saltar al contenido principal
En esta página

Requisitos previos#

Antes de implementar Monedero de la aplicación Deuna pagos, asegúrese de tener:

  • Habilitado Monedero de la aplicación Deuna en el panel de administración de Deuna
  • generó un ficha de pedido a través de la API de Deuna
  • Integrado SDK de Deuna en tu proyecto
  • Revisé la documentación del Widget de Pago para tu plataforma
  • Seleccionó su preferido modo de pago (Código numérico o QR) en el Panel de administración

Configuración del widget de pago#

Implementación básica

Inicialice el widget de pago con el deuna_wallet procesador:

JavaScript
DeunaSDK.initPaymentWidget({
  orderToken: '',
  paymentMethods: [
    {
      paymentMethod: 'voucher',
      processors: ['deuna_wallet'],
    },
  ],
  callbacks: {
    onSuccess: (data) => {
      console.log('Payment successful:', data);
      // Redirect to success page
    },
    onError: (error) => {
      console.log('Payment failed:', error);
      // Show error message to user
    },
    onPending: (data) => {
      console.log('Payment pending confirmation:', data);
      // Show waiting screen
    },
  },
});

Ejemplo completo con todas las opciones

JavaScript
DeunaSDK.initPaymentWidget({
  orderToken: '',
  paymentMethods: [
    {
      paymentMethod: 'voucher',
      processors: ['deuna_wallet'],
      metadata: {
        // Optional: Pass additional data
        orderId: 'your-internal-order-id',
      },
    },
  ],
  callbacks: {
    onSuccess: (response) => {
      console.log('Payment confirmed:', {
        orderId: response.order_id,
        orderToken: response.order_token,
        status: response.status,
        amount: response.amount,
        currency: response.currency,
      });
      
      // Verify payment on your backend
      fetch('/api/verify-payment', {
        method: 'POST',
        body: JSON.stringify({
          orderToken: response.order_token,
          orderId: response.order_id,
        }),
      })
      .then(res => res.json())
      .then(data => {
        if (data.verified) {
          window.location.href = '/order-confirmation';
        }
      });
    },
    
    onError: (error) => {
      console.error('Payment error:', {
        code: error.code,
        message: error.message,
      });
      
      // Show user-friendly error message
      showErrorModal({
        title: 'Payment Failed',
        message: 'Unable to process your payment. Please try again.',
      });
    },
    
    onPending: (response) => {
      console.log('Payment pending user confirmation:', {
        orderId: response.order_id,
        expiresAt: response.expires_at,
      });
    },
    
    onExpired: (response) => {
      console.log('Payment code/QR expired:', {
        orderId: response.order_id,
        expiredAt: response.expired_at,
      });
    },
  },
});

Modos de pago#

Comprender los dos modos

Su cuenta mercantil está configurada con uno de estos modos en el Panel de administración:

Modo 1: Código numérico (ventana de 3 minutos)

Lo que ve el cliente:

  • Un código numérico de 6 dígitos que se muestra en la pantalla.
  • Temporizador de cuenta atrás que muestra el tiempo restante (0:00-3:00)
  • Instrucciones para abrir la aplicación Deuna e ingresar el código

Flujo de clientes:

  1. Toma nota del código de 6 dígitos
  2. Abre la aplicación Deuna
  3. Selecciona "Pagar con código"
  4. Ingresa el código de 6 dígitos
  5. Confirma el pago en la aplicación
  6. Pago confirmado inmediatamente a través de webhook

Configuración: Establecer en el Panel de administración en la configuración del procesador de Deuna App Wallet

Modo 2: Código QR (ventana de 15 minutos)

Lo que ve el cliente:

  • Un código QR dinámico en pantalla
  • Temporizador de cuenta atrás que muestra el tiempo restante (0:00-15:00)
  • Dos opciones para proceder:
    • Escanea QR con la cámara de la aplicación Deuna
    • Haga clic en QR para abrir la aplicación directamente

Flujo de clientes:

  1. Opción A - Escanear:

    • Abre la cámara de la aplicación Deuna
    • Escanea el código QR
    • La página de pago se abre automáticamente
    • Confirma el pago en la aplicación
    • Pago confirmado mediante webhook
  2. Opción B - Haga clic en:

    • Hace clic en el código o botón QR
    • Abre la aplicación Deuna directamente
    • Muestra la pantalla de confirmación de pago.
    • Confirma el pago
    • Pago confirmado mediante webhook

Configuración: Establecer en el Panel de administración en la configuración del procesador de Deuna App Wallet

Nota: La selección del modo ocurre una vez durante la configuración inicial en el Panel de administración. Todos los pedidos posteriores utilizarán el modo configurado. Póngase en contacto con el soporte de Deuna para cambiar los modos.

Manejo de la confirmación de pago#

Confirmación basada en webhook (principal)

La App Wallet de Deuna envía una notificación de webhook a su backend cuando el cliente confirma el pago:

JavaScript
// Your backend webhook endpoint
app.post('/webhooks/deuna-wallet', (req, res) => {
  const { order_id, order_token, status, amount, currency } = req.body;
  
  // Verify webhook signature (recommended)
  const isValid = verifyWebhookSignature(req);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Handle confirmation
  if (status === 'confirmed') {
    // Update your database
    updateOrder(order_id, {
      status: 'paid',
      paidAt: new Date(),
      amount: amount,
      currency: currency,
    });
    
    // Send confirmation email to customer
    sendConfirmationEmail(order_id);
  }
  
  // Acknowledge receipt
  res.json({ success: true });
});

Reserva de sondeo (secundaria)

Si la entrega del webhook se retrasa o falla, el sistema sondea el /order punto final cada 3 segundos:

JavaScript
// Client-side polling (handled automatically by SDK)
// But you can also implement it manually if needed

const pollOrderStatus = async (orderToken) => {
  const maxAttempts = 60; // 3 minutes for numeric code
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    try {
      const response = await fetch(`/api/order/${orderToken}`);
      const order = await response.json();
      
      if (order.status === 'confirmed') {
        handlePaymentSuccess(order);
        return;
      }
      
      if (order.status === 'expired') {
        handlePaymentExpired(order);
        return;
      }
      
      // Wait 3 seconds before polling again
      await new Promise(resolve => setTimeout(resolve, 3000));
      attempts++;
      
    } catch (error) {
      console.error('Polling error:', error);
    }
  }
  
  handlePaymentExpired();
};

Objetos de respuesta#

Respuesta exitosa

Cuando se confirme el pago, onSuccess la devolución de llamada recibe:

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "confirmed",
  payment_method: "deuna_wallet",
  amount: 99.99,
  currency: "USD",
  timestamp: "2024-03-20T14:30:45Z",
  metadata: {
    // Any metadata passed during initialization
  }
}

Respuesta de error

Cuando el pago falla, onError la devolución de llamada recibe:

JavaScript
{
  code: "PAYMENT_FAILED",
  message: "Unable to process payment",
  order_id: "order_abc123def456",
  details: {
    reason: "Insufficient funds in Deuna wallet"
  }
}

Pendiente de respuesta

Mientras espera la confirmación del usuario, onPending la devolución de llamada recibe:

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "pending",
  payment_method: "deuna_wallet",
  code_or_qr: "123456", // For numeric code mode
  expires_at: "2024-03-20T14:33:45Z",
  expires_in_seconds: 180
}

Respuesta caducada

Cuando el código/QR caduque, onExpired la devolución de llamada recibe:

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "expired",
  payment_method: "deuna_wallet",
  expired_at: "2024-03-20T14:33:45Z",
  message: "Code has expired"
}

Mejores prácticas de interfaz de usuario#

Para el modo de código numérico

  • Mostrar el código de forma destacada - Fuente grande y clara
  • Mostrar temporizador de cuenta regresiva - Actualizar cada segundo
  • Mostrar instrucciones claras:
    • "Abre la aplicación Deuna"
    • "Seleccione Pagar con Código"
    • "Ingrese este código de 6 dígitos"
    • "Confirmar pago"
  • Mostrar estado de vencimiento - Cuando el código caduca después de 3 minutos
  • Proporcionar opción de regeneración - Botón "Generar nuevo código"

Para el modo de código QR

  • Mostrar el código QR de forma destacada - Centrado, escalable
  • Mostrar temporizador de cuenta regresiva - Actualizar cada segundo
  • Proporcionar dos opciones de interacción:
    • Escanea QR con la aplicación Deuna
    • Haga clic en QR para abrir la aplicación directamente
  • Mostrar instrucciones claras
  • Mostrar estado de vencimiento - Cuando el QR caduca después de 15 minutos
  • Proporcionar opción de regeneración - Botón "Generar nuevo código"

Pautas generales

  • Mantener modal/pantalla abierta - No redirigir ni cerrar hasta que el pago se confirme o caduque
  • Desactivar otros métodos de pago - Evitar seleccionar otro método mientras espera
  • Responsivo móvil - Garantizar la legibilidad en pantallas pequeñas
  • Accesibilidad - Incluya texto alternativo para QR, contraste de color claro para temporizadores
  • Estados de carga - Mostrar ruleta mientras genera código/QR

Patrones de implementación comunes#

Patrón de gancho de reacción

JavaScript
import { useEffect, useState } from 'react';

export const useDeunaWalletPayment = (orderToken) => {
  const [status, setStatus] = useState('idle'); // idle | pending | success | error | expired
  const [expiresAt, setExpiresAt] = useState(null);

  useEffect(() => {
    if (!orderToken) return;

    DeunaSDK.initPaymentWidget({
      orderToken,
      paymentMethods: [
        {
          paymentMethod: 'voucher',
          processors: ['deuna_wallet'],
        },
      ],
      callbacks: {
        onPending: (data) => {
          setStatus('pending');
          setExpiresAt(data.expires_at);
        },
        onSuccess: (data) => {
          setStatus('success');
        },
        onError: (error) => {
          setStatus('error');
        },
        onExpired: () => {
          setStatus('expired');
        },
      },
    });
  }, [orderToken]);

  const regenerate = () => {
    setStatus('idle');
    window.location.reload();
  };

  return { status, expiresAt, regenerate };
};