Skip to main content
The Payment Widget provides a seamless way to integrate Uphold’s payment capabilities into your applications. Integration is achieved through the Payment Widget SDK, which can be used in both web and native applications. For web applications, the SDK integrates directly into your JavaScript/TypeScript code. For native applications (iOS/Android), the SDK runs within a WebView component, providing the same functionality in a native app environment.

Prerequisites

Before integrating the Payment Widget, ensure you have:
  • Access to Uphold’s Enterprise REST API - Get in touch with an Uphold Sales representative or your Uphold Account Manager to get started.

Installation

The Payment Widget SDK is available as an NPM package. Install it in your project:
npm install @uphold/enterprise-payment-widget-web-sdk

Web Application Integration

For web applications, import and use the SDK directly in your JavaScript/TypeScript code:
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

// Create a Payment Widget session (See the 'Use Cases' pages for examples)
const session = createPaymentWidgetSession();

// Create the Widget instance
const widget = new PaymentWidget(session, { debug: true });

// Set up event handlers
widget.on('complete', (event) => {
  console.log('Payment completed:', event.detail.value);
  widget.unmount();
});

widget.on('cancel', () => {
  console.log('Payment cancelled');
  widget.unmount();
});

widget.on('error', (event) => {
  console.error('Payment error:', event.detail.error);
  widget.unmount();
});

// Mount the Widget's iframe to a DOM element
widget.mountIframe(document.getElementById('payment-container'));
The session parameter is a payment session object created through the Create Session endpoint. The specific session creation process and parameters vary depending on your use case. See the individual use case pages (Select for Deposit, Select for Withdrawal, Authorize) for detailed examples of how to create sessions for each flow.

Native Application Integration

Native mobile applications integrate the Payment Widget using a WebView component that loads an HTML page containing the Payment Widget SDK. To handle Payment Widget events, your native application needs to implement a communication bridge between the WebView and native code. This bridge enables your native app to receive and respond to events from the Payment Widget.

HTML Template for WebView

Create an HTML file that includes the Payment Widget SDK in your js bundle:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Payment Widget</title>
    <style>
      body { margin: 0; padding: 0; }
      #payment-container { width: 100%; height: 100vh; }
    </style>
  </head>
  <body>
    <div id="payment-container"></div>

    <!-- Include your JS bundle which contains the SDK -->
    <script src="your-bundle-with-sdk.js"></script>
    <script>
      // Initialize Widget when page loads
      window.addEventListener('load', () => {
        const session = createPaymentWidgetSession();

        const widget = new PaymentWidget(session);

        widget.on('complete', (event) => {
          sendToNativeApp('complete', event.detail);
          widget.unmount();
        });

        widget.on('cancel', () => {
          sendToNativeApp('cancel');
          widget.unmount();
        });

        widget.on('error', (event) => {
          sendToNativeApp('error', event.detail.error);
          widget.unmount();
        });

        widget.mountIframe(document.getElementById('payment-container'));
      });

      // Helper function to send events to native app
      function sendToNativeApp(type, data = null) {
        const message = { type, data };

        if (window.webkit?.messageHandlers?.paymentWidgetMessage) {
          // iOS - send all events through single handler
          window.webkit.messageHandlers.paymentWidgetMessage.postMessage(message);
        } else if (window.PaymentBridge) {
          // Android - send events through JavaScript interface
          window.PaymentBridge.onMessage(JSON.stringify(message));
        } else if (window.ReactNativeWebView) {
          // React Native - send events through postMessage
          window.ReactNativeWebView.postMessage(JSON.stringify(message));
        }
      }
    </script>
  </body>
</html>

Setting Up the WebView

Now that you have the HTML template, you need to set up the WebView in your native application to load this HTML file and configure event listeners to react to the Payment Widget events.
import WebKit

class PaymentViewController: UIViewController, WKScriptMessageHandler {
  @IBOutlet weak var webView: WKWebView!

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set up single message handler for all Payment Widget events
    let contentController = webView.configuration.userContentController
    contentController.add(self, name: "paymentWidgetMessage")

    // Load your HTML file with the Payment Widget
    if let url = Bundle.main.url(forResource: "payment-widget", withExtension: "html") {
      webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
    }
  }

  // Handle messages from the WebView
  func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "paymentWidgetMessage" {
      guard let messageDict = message.body as? [String: Any],
          let type = messageDict["type"] as? String else {
        return
      }

      let data = messageDict["data"]

      switch type {
        case "complete":
          handlePaymentComplete(data: data)
        case "cancel":
          handlePaymentCancel()
        case "error":
          handlePaymentError(error: data)
        default:
          print("Unknown Payment Widget message type: \(type)")
      }
    }
  }

  private func handlePaymentComplete(data: Any?) {
    // Handle successful payment completion
    print("Payment completed: \(data ?? "no data")")
    // Navigate to success screen or handle completion
  }

  private func handlePaymentCancel() {
    // Handle payment cancellation
    print("Payment cancelled")
    // Navigate back or show cancellation message
  }

  private func handlePaymentError(error: Any?) {
    // Handle payment error
    print("Payment error: \(error ?? "unknown error")")
    // Show error message to user
  }
}
import android.webkit.WebView;
import android.webkit.WebSettings;
import android.webkit.JavascriptInterface;
import android.util.Log;
import org.json.JSONObject;

// Set up WebView
WebView webView = findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);

// Add JavaScript interface to handle events from WebView
webView.addJavascriptInterface(new PaymentBridge(), "PaymentBridge");

// Load your HTML file with the Payment Widget
webView.loadUrl("file:///android_asset/payment-widget.html");

// JavaScript interface class to handle WebView events
public class PaymentBridge {
  @JavascriptInterface
  public void onMessage(String messageJson) {
    try {
      JSONObject message = new JSONObject(messageJson);
      String type = message.getString("type");
      Object data = message.opt("data");

      runOnUiThread(() -> {
        switch (type) {
          case "complete":
            handlePaymentComplete(data != null ? data.toString() : null);
            break;
          case "cancel":
            handlePaymentCancel();
            break;
          case "error":
            handlePaymentError(data != null ? data.toString() : null);
            break;
          default:
            Log.w("Payment", "Unknown Payment Widget message type: " + type);
        }
      });
    } catch (Exception e) {
      Log.e("Payment", "Error parsing Payment Widget message", e);
    }
  }

  private void handlePaymentComplete(String data) {
    // Handle successful payment completion
    Log.d("Payment", "Payment completed: " + data);
    // Navigate to success screen or handle completion
  }

  private void handlePaymentCancel() {
    // Handle payment cancellation
    Log.d("Payment", "Payment cancelled");
    // Navigate back or show cancellation message
  }

  private void handlePaymentError(String error) {
    // Handle payment error
    Log.e("Payment", "Payment error: " + error);
    // Show error message to user
  }
}
import { WebView } from 'react-native-webview';
import { Alert } from 'react-native';

const PaymentScreen = () => {
  const handleMessage = (event) => {
    try {
      const message = JSON.parse(event.nativeEvent.data);

      switch (message.type) {
        case 'complete':
          handlePaymentComplete(message.data);
          break;
        case 'cancel':
          handlePaymentCancel();
          break;
        case 'error':
          handlePaymentError(message.data);
          break;
        default:
          console.log('Unknown message type:', message.type);
      }
    } catch (error) {
      console.error('Error parsing WebView message:', error);
    }
  };

  const handlePaymentComplete = (data) => {
    // Handle successful payment completion
    console.log('Payment completed:', data);
    Alert.alert('Success', 'Payment completed successfully!');
    // Navigate to success screen
  };

  const handlePaymentCancel = () => {
    // Handle payment cancellation
    console.log('Payment cancelled');
    Alert.alert('Cancelled', 'Payment was cancelled');
    // Navigate back
  };

  const handlePaymentError = (error) => {
    // Handle payment error
    console.error('Payment error:', error);
    Alert.alert('Error', 'An error occurred during payment');
    // Show error message or retry option
  };

  return (
    <WebView
      source={{ uri: 'file:///path/to/payment-widget.html' }}
      javaScriptEnabled={true}
      domStorageEnabled={true}
      onMessage={handleMessage}
    />
  );
};

Next Steps

Now that you understand how to integrate the Payment Widget SDK, explore what you can do:

Use Cases

Additional Resources

FAQ

Q: The Payment Widget does not show when running locally, what is the cause? A: This might be due to Content Security Policy (CSP) settings. Check your framework documentation on how to configure CSP to allow the Payment Widget iframe to be loaded.
I