Postmessage events

This page details the events, implementation examples, and recommendations on how to act upon receiving and processing these events, facilitating a seamless integration into your payment system.

DEUNA handles standardized events via postMessage to report on transaction progress, improving the user experience and ensuring secure transactions.

📘

Event handling is crucial for the proper functioning of DEUNA SDKs.

JavaScript postMessage function

The JavaScript postMessage function is crucial for secure communication between iFrames and windows in web applications. It's especially important in the context of online payments, where protecting user data is essential.

The JavaScript postMessage function allows systems to securely exchange information between the payment system and the merchant's website, ensuring that sensitive data, such as credit card information, is handled with the utmost security.

Event table

EventoMeta-PayloadDescripción
VaultStartedNoneEmitted when the widget has loaded and the user can now interact with the page elements.
VaultSaveSuccess- createdCard: bankName (string)
- cardId (string)
- company (string)
- firstSix (string)
- lastFour (string)
- userId (string)
- storedCard (boolean)
storecard is true if the card was selected from the user's saved cards.
False if it is new
Issued when the creation of a card in DEUNA is successfully completed.
VaultSaveError- errorMessage
- errorCode
Triggered when an error occurs in card creation.
VaultFailed- errorCode
- errorMessage
For general errors during loading.
VaultProcessingN/AEmit when the user clicks on the action button and while the DEUNA API responds.
onBinDetectedProvided as metadata

- card_bin: card BIN

- card_brand: card brandThis data will only be sent if:

- BIN is entered
-System detects the BIN entryIt is subsequently deleted.No metadata will be sent to inform the merchant not to send it in the transaction.
Issued upon recognizing any change in the BIN entry.
onInstallmentSelectedparsedData.data?.metadata?.plan_option_id
This ID contains the selected installment option that should be sent in the Purchase API
This event is emitted when the user selects an option from the installments dropdown..
vaultSaveClickN/AIssued when the user clicks the continue/pay button.
paymentMethodsCardNumberEnteredN/AIssued when the user finishes adding all the card digits.
paymentMethodsCardNumberInitiatedN/AIssued when the user selects the card number field.
paymentMethodsCardExpirationDateInitiatedN/AEmitted when the user selects the expiration date field.
paymentMethodsCardExpirationDateEnteredN/AEmitted when the user finishes adding the expiration date.
paymentMethodsCardSecurityCodeInitiatedN/AEmitted when the user selects the CVV field.
paymentMethodsCardSecurityCodeEnteredN/AIssued when the user finishes adding the CVV.
paymentMethodsCardNameInitiatedN/AIssued when the user selects the cardholder name field.
paymentMethodsCardNameEnteredN/AIssued when the user adds at least two words separated by a space (without special characters or numbers).

Reproduce VaultSaveError and VaultFailed:

  1. Change the public key for another value after the elements URL charges.
  2. Use the test card 1354 1001 4004 955

Examples

Compare the postMessage event examples:

window.addEventListener("message", (event) => {
  // Verify message origin for safety
  if (event.origin !== "URL_DE_CONFIANZA") {
    return;
  }

  // Procesar el evento recibido
  switch (event.data.type) {
    case 'VaultStarted':
      console.log("VaultStarted: Click to Pay está listo para la interacción.");
      // Impement actions after payment process is started
      break;

    case 'VaultSaveSuccess':
      const cardId = event.data.metadata.createdCard.id;
      console.log(`VaultSaveSuccess: Tarjeta guardada con éxito. ID de la tarjeta: ${cardId}`);
      // Manage card creation success and procede to payment process
      break;

    case 'VaultSaveError':
    case 'VaultFailed':
      const errorCode = event.data.metadata.errorCode;
      const errorMessage = event.data.metadata.errorMessage;
      console.error(`${event.data.type}: Error en el proceso. Código: ${errorCode}, Mensaje: ${errorMessage}`);
      // Manage errors in card saving or other general error
      break;

    case 'VaultProcessing':
      console.log("VaultProcessing: Procesando pago con DEUNA.");
      // Implement actions while payment is processing
      break;
    case 'onBinDetected':
    	// When user inputs first six digits of card
      const cardBrand = event.data?.metadata?.cardBrand;
    case 'onInstallmentSelected':
    	// When user selects quantity of installments
    	const planOptionId = event.data.metadata.plan_option_id;
   case 'onBinEmpty':
    	// Cuando el usuario limpia el BIN
    default:
      console.warn(`Evento no reconocido: ${event.data.type}`);
      // Manage  non specified cases
      break;
  }
});
// Step 1: Implement the following delegates: WKNavigationDelegate, WKUIDelegate 

// Step 2: Define the webView and override the window.open behaviour

 let configuration = WKWebViewConfiguration()
 private var webView: WKWebView?


 var scriptSource = """
    window.open = function(open) {
        return function(url, name, features) {
            location.href = url; // or window.location.replace(url)
        };
    }(window.open);
    """

// Step 3: Initialize the webView

/// Loads the web view with the specified URL.
/// Parameter urlString: The URL string to load.
func loadUrl(urlString: String) {
  let userScript = WKUserScript(
    source: scriptSource,
    injectionTime: .atDocumentStart,
    forMainFrameOnly: false
  )

  self.configuration.preferences.javaScriptEnabled = true
  self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
  self.configuration.userContentController.addUserScript(userScript)
  self.configuration.userContentController.add(self, name: "deuna") // IMPORTANT the name "deuna"

  self.webView = WKWebView(
    frame: view.bounds,
    configuration: self.configuration
  )

  self.webView!.navigationDelegate = self

  if let url = URL(string: urlString) {
    let request = URLRequest(url: url)
    self.webView?.load(request)
  }
}

// Step 4: Define the function to listen when the URL of the widget
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  view.addSubview(webView)
  self.adjustScrolling(webView: webView)
}

// Listen to the PostMessages
// Gets the data from the script message as Foundation Data.
//    - Parameter message: The script message.
//    - Returns: The data from the script message, if available.
func getMessageData(message: WKScriptMessage) -> Foundation.Data? {
  guard let jsonString = message.body as? String else {
    return nil
  }
  return jsonString.data(using: .utf8)
}

/// Handler for receiving JavaScript messages.
///
/// - Parameters:
///   - userContentController: The user content controller.
///   - message: The message received.
func userContentController(
  _ userContentController: WKUserContentController,
  didReceive message: WKScriptMessage
) {
  // Attempt to decode the received JSON message
  guard let jsonData = getMessageData(message: message) else {
    return
  }

  do {
    // Decode the JSON message 
    let decoder = JSONDecoder()
    // listen the post message data
  } catch {

  }
}
// Step 1: Create and show the WebView
lateinit var webView: WebView
    
private fun initialize() {
  webView = findViewById(R.id.deuna_webview)
}

// Step 2: Enable JS and pass over the interface to listen the postMessages and show the URL
// Load the URL in the WebView
@SuppressLint("SetJavaScriptEnabled")
fun loadUrl(url: String) {

  webView.settings.apply {
    domStorageEnabled = true
    javaScriptEnabled = true
    setSupportMultipleWindows(true) // Enable support for multiple windows
  }

  // Add JavascriptInterface
  webView.addJavascriptInterface(WebViewBridge(), "android") // IMPORTANT the name "android"

  webView.webViewClient = object : WebViewClient() {
    override fun onPageFinished(view: WebView?, url: String?) {
      super.onPageFinished(view, url)
      // When the page finishes loading, the Web View is shown and the loader is hidden
    }
  }
  webView.loadUrl(url)
}

// Step 3: To create a class with a postMessage function using the @javascriptInterface annotation and listen for post message events
// Class to handle communication between the WebView and the native Android code
class WebViewBridge {
  /**
   * The postMessage function is called when a message is received from JavaScript code in a WebView.
   * The message is parsed and the corresponding callbacks are called based on the event type.
  */
  @JavascriptInterface
  fun postMessage(message: String) {
    try {
      val json = JSONObject(message)
      // listen the post message events
    } catch (e: Exception) {
      Log.d("WebViewBridge", "postMessage: $e")
    }
  }

  abstract fun handleEvent(message: String)
}

Post-event capture actions

After capturing an event, start a process in your backend to make a call to Crear Pago.

This ensures the effective completion of the payment transaction, following our security and data handling guidelines