Skip to main content
On this page

Use the DEUNA React Native SDK to share Payment Widget, Payment Vault, Click to Pay, next-action, voucher, and native-wallet integrations across iOS and Android.

Install#

Install the SDK and its WebView peer dependency.

npm install @deuna/react-native-sdk react-native-webview

React Native CLI

Autolinking registers the native modules. Install iOS pods after adding or upgrading the package:

Shell
npx pod-install

The 2.1 and later releases include native Apple Pay, Google Pay, and fraud modules. Review the repository’s native setup notes for the current Xcode and Android dependency-compatibility blocks required by a bare React Native project.

Expo

Add the config plugin. Supply only the wallet entitlements and fraud providers your application uses.

app.jsonJSON
{
  "expo": {
    "plugins": [
      [
        "@deuna/react-native-sdk",
        {
          "merchantIdentifiers": ["merchant.com.example"],
          "googlePay": true,
          "fraudProviders": []
        }
      ]
    ]
  }
}

Regenerate the native projects after changing the plugin configuration:

Shell
npx expo prebuild

Because the SDK contains native modules, test it in a development build rather than Expo Go.

Initialize and mount the renderer#

Create one SDK instance and retain it across renders. Mount exactly one DeunaWidget for that instance. The component renders both modal and embedded WebView flows; calling an initializer only configures its controller.

JavaScript
import {useMemo} from 'react';
import {DeunaSDK, DeunaWidget} from '@deuna/react-native-sdk';

export function CheckoutScreen() {
  const deunaSDK = useMemo(
    () =>
      DeunaSDK.initialize({
        publicApiKey: 'YOUR_PUBLIC_API_KEY',
        environment: 'sandbox',
      }),
    []
  );

  return (
    <>
      <CheckoutContent deunaSDK={deunaSDK} />
      <DeunaWidget instance={deunaSDK} />
    </>
  );
}

Open Payment Widget#

Use Mode.MODAL for an SDK-owned modal. The previously mounted DeunaWidget reacts to the initialized controller.

JavaScript
import {Mode} from '@deuna/react-native-sdk';

await deunaSDK.initPaymentWidget({
  orderToken,
  mode: Mode.MODAL,
  language: 'en',
  callbacks: {
    onSuccess: async (order) => {
      await deunaSDK.close();
      navigation.navigate('PaymentSuccess', {order});
    },
    onError: (error) => showRetry(error),
    onClosed: (action) => navigation.goBack(),
    onPaymentProcessing: () => disablePayButton(),
    onEventDispatch: (event, payload) => {
      analytics.track(event, payload);
    },
  },
});

Use the callback to update the interface. Confirm and fulfill the final order from a verified webhook rather than trusting application state alone.

Embed a widget#

Initialize with Mode.EMBEDDED and render DeunaWidget inside the screen layout instead of mounting it beside the screen.

JavaScript
await deunaSDK.initPaymentWidget({
  orderToken,
  mode: Mode.EMBEDDED,
  callbacks,
});
JavaScript
<View style={{flex: 1}}>
  <DeunaWidget instance={deunaSDK} />
</View>

Do not render the same SDK instance in both locations. Unmounting DeunaWidget disposes its active controller.

If your application owns the pay button, set hidePayButton: true, then call isValid() and submit() from the button action.

JavaScript
const handlePay = async () => {
  if (!(await deunaSDK.isValid())) return;
  const result = await deunaSDK.submit();
  if (result.status === 'error') showRetry(result);
};

Available experiences#

ExperienceMethodImportant input
Payment WidgetinitPaymentWidget(...)orderToken, callbacks, optional mode
Payment VaultinitElements(...)callbacks; types may be omitted
Click to PayinitElements(...)types: [{name: 'click_to_pay'}]
Next ActioninitNextAction(...)order token, callbacks, and mode
VoucherinitVoucherWidget(...)order token, callbacks, and mode

The SDK also exposes setCustomStyle(...), refetchOrder(), getWidgetState(), isValid(), submit(), and close() for the active controller.

Payment Vault and Click to Pay#

Payment Vault is the default Elements experience. Pass either an authenticated userToken or userInfo for the customer.

JavaScript
await deunaSDK.initElements({
  orderToken,
  userInfo: {email: 'ada@example.com'},
  types: [{name: 'vault'}],
  mode: Mode.MODAL,
  callbacks: {
    onSuccess: (credential) => useSavedCredential(credential),
    onError: (error) => showRetry(error),
    onClosed: (action) => showPaymentMethods(action),
  },
});

Use {name: 'click_to_pay'} for Click to Pay.

Native Apple Pay and Google Pay#

Check merchant configuration and device support before rendering a wallet button. The returned values are apple_pay and google_pay.

JavaScript
const userInfo = {email: 'ada@example.com'};
const wallets = await deunaSDK.getWalletsAvailable({
  orderToken,
  userInfo,
});

setShowApplePay(wallets.includes('apple_pay'));
setShowGooglePay(wallets.includes('google_pay'));

After availability succeeds, launch the native sheet from the button press. For Apple Pay, keep this call directly in the user gesture.

JavaScript
const launchWallet = (provider: 'apple_pay' | 'google_pay') => {
  const type = provider === 'apple_pay' ? 'APPLE_PAY' : 'GOOGLE_PAY';

  deunaSDK.initElements({
    orderToken,
    userInfo,
    types: [{name: type}],
    callbacks: {
      onSuccess: (credential) => useSavedCredential(credential),
      onError: (error) => showRetry(error),
      onClosed: () => showPaymentMethods(),
    },
  });
};

Apple Pay requires the iOS entitlement and merchant identifier. Google Pay requires merchant enablement and an eligible Android device. See Apple Pay and Google Pay.

Continue a pending action#

Use the same order token when DEUNA reports that the payment requires a supported 3DS challenge or redirect.

JavaScript
await deunaSDK.initNextAction({
  orderToken,
  mode: Mode.MODAL,
  callbacks: {
    onSuccess: (order) => showConfirmation(order),
    onError: (error) => showRetry(error),
    onClosed: () => showPaymentMethods(),
  },
});

Open a voucher#

JavaScript
await deunaSDK.initVoucherWidget({
  orderToken,
  mode: Mode.MODAL,
  callbacks: {
    onSuccess: (order) => showVoucherInstructions(order),
    onError: (error) => showRetry(error),
    onClosed: () => showPaymentMethods(),
    onDownloadFile: (file) => saveVoucher(file),
  },
});

Handle external redirects#

The default adapter opens external URLs with React Native Linking. Payment methods that require Chrome Custom Tabs or SFSafariViewController need an InAppBrowserAdapter supplied during initialization.

JavaScript
const deunaSDK = DeunaSDK.initialize({
  publicApiKey: 'YOUR_PUBLIC_API_KEY',
  environment: 'sandbox',
  inAppBrowserAdapter: myInAppBrowserAdapter,
});

The adapter must implement openUrl(url) and resolve after the external browser closes. See the repository’s adapter migration examples.

Fraud-device data#

Pre-initialize linked providers before the customer reaches payment, then generate the combined identifier when your order or risk flow needs it.

JavaScript
await deunaSDK.initializeFraudProviders({
  MERCADOPAGO: {},
});

const fraudId = await deunaSDK.generateFraudId({
  MERCADOPAGO: {},
});

Expo projects must also list the lower-case provider name in the config plugin, for example fraudProviders: ['mercadopago'], and rerun expo prebuild. Bare projects must link the matching native dependency. See Integrate device fingerprint.

Callback and lifecycle reference#

Callback or methodUse it for
onSuccessUpdate the interface after the experience succeeds.
onErrorRead type and metadata and present retry behavior.
onClosedDistinguish customer and SDK-controlled closure.
onEventDispatchObserve supported payment or Elements lifecycle events.
onCardBinDetectedReact to card BIN detection.
onInstallmentSelectedReact to an installment-plan selection.
onPaymentProcessingPrevent duplicate payment actions.
onDownloadFileHandle voucher files returned as a URL or base64 data.
close()Close the active controller and external-view state.

Official examples and source#

See ModalScreen.tsx, EmbeddedScreen.tsx, and WalletsScreen.tsx for complete runnable flows.