npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moonpay/platform-sdk-react-native

v1.9.0

Published

MoonPay Developer Platform SDK for React Native

Readme

@moonpay/platform-sdk-react-native

React Native SDK for the MoonPay Developer Platform. Connect customers to MoonPay, fetch quotes and payment methods, and render MoonPay frames (widget, Apple Pay, Google Pay, buy, add-card, challenge) as WebViews in your React Native app.

React Native guides are not yet published on dev.moonpay.com — this README is the current starting point. The platform concepts (sessions, connections, quotes, frames) are the same as for the web SDK, so the existing guides still apply.

Installation

npm install @moonpay/platform-sdk-react-native react-native-webview

For Expo projects:

npx expo install react-native-webview
npm install @moonpay/platform-sdk-react-native

Peer dependencies:

  • react >= 18
  • react-native >= 0.73 (Hermes supported)
  • react-native-webview >= 13

The SDK's crypto layer is pure JavaScript (@noble libraries) — no native modules or polyfills required.

Quick start

1. Create a session server-side with @moonpay/platform-sdk-node and pass the session token to your app:

// On your server — never ship your API key in the app
import { createServerClient } from '@moonpay/platform-sdk-node';

const server = createServerClient({ apiKey: process.env.MOONPAY_API_KEY });

const result = await server.createSession({
  externalCustomerId: 'customer-123',
  deviceIp: customerIp,
});

if (result.ok) {
  // Send result.value.sessionToken to your app
}

2. Wrap your app in MoonPayProvider with the session token:

import { MoonPayProvider } from '@moonpay/platform-sdk-react-native';

export function App() {
  return (
    <MoonPayProvider sessionToken={sessionToken}>
      <YourApp />
    </MoonPayProvider>
  );
}

MoonPayProvider also accepts optional apiBaseUrl and frameBaseUrl props that point the SDK at a different MoonPay environment — useful if MoonPay gives you test endpoints during onboarding. Leave them unset to use production.

Pass an optional theme={{ appearance: 'light' | 'dark' }} to render every MoonPay frame in light or dark mode. Omit it to follow the customer's system preference. The connect flow can override it per call (client.connect({ theme }) or <MoonPayConnect theme={...} />).

3. Check the connection and connect the customer:

import { Button } from 'react-native';
import { useMoonPay } from '@moonpay/platform-sdk-react-native';

function BuyScreen() {
  const { client } = useMoonPay();

  const startConnect = async () => {
    const connection = await client.getConnection();
    if (!connection.ok) {
      console.error(connection.error);
      return;
    }

    if (connection.value.status === 'connectionRequired') {
      // Presents the connect flow full-screen so the customer can sign in to MoonPay
      await client.connect({
        onEvent: (event) => console.log(event.kind),
      });
    }
  };

  return <Button title="Get started" onPress={startConnect} />;
}

All client methods return a Result<T, E> discriminated union instead of throwing — check result.ok before using result.value.

Connection statuses

getConnection() resolves with one of six statuses. Handle connectionRequired and active at minimum:

| Status | Meaning | What to do | |--------|---------|------------| | connectionRequired | New or expired customer | Run the connect flow — client.connect() or <MoonPayConnect>. Headless integrations: <MoonPayAuth> | | active | Customer is connected | Proceed — quotes, payment methods, and payment frames are ready to use | | pending | KYC decision is delayed | Show a waiting state; the status can resolve to active on a later visit | | failed | Terminal failure, such as a KYC rejection | Do not retry the connect flow; the reason field describes the failure | | unavailable | Customer is in a restricted location | Hide MoonPay functionality | | termsAcceptanceRequired | Headless integrations only — the customer has no valid Terms of Use attestation on file | Show the Terms of Use in your UI, capture acceptance via POST /platform/v1/terms/attestations, then check the connection again |

Two ways to render frames

The SDK supports both a declarative and an imperative style:

  • Components (<MoonPayWidget>, <MoonPayApplePayButton>, …) render inline wherever you place them in your layout. Prefer these — you keep full control over placement, styling, and navigation.
  • Client methods (client.setupWidget(), client.connect(), …) present the frame in a full-screen modal managed by the SDK. Useful when you want a flow to take over the screen without layout work.

Headless frames (<MoonPayConnectionCheck>, <MoonPayBuyFrame>, <MoonPayConnectionReset>) render nothing visible — they run a flow in a hidden WebView and report results through onEvent.

Examples

Connect a customer inline

Render the connect flow as part of your own screen instead of a modal:

import { MoonPayConnect } from '@moonpay/platform-sdk-react-native';

function ConnectScreen({ onConnected }: { onConnected: () => void }) {
  return (
    <MoonPayConnect
      theme={{ appearance: 'dark' }}
      onEvent={(event) => {
        if (event.kind === 'complete') onConnected();
      }}
    />
  );
}

On completion, credentials are applied to the shared client automatically — you can call payment methods right away.

Authenticate with email and OTP (headless)

Identity API partners can use <MoonPayAuth> instead of the full connect flow — it drives the customer through email and OTP authentication only. The auth frame needs a clientToken, which the SDK stores automatically when getConnection() resolves with connectionRequired, so always check the connection first:

import { useState } from 'react';
import { Button } from 'react-native';
import { MoonPayAuth, useMoonPay } from '@moonpay/platform-sdk-react-native';

function SignInScreen({ onAuthenticated }: { onAuthenticated: () => void }) {
  const { client } = useMoonPay();
  const [showAuth, setShowAuth] = useState(false);

  const start = async () => {
    const connection = await client.getConnection();
    if (connection.ok && connection.value.status === 'connectionRequired') {
      setShowAuth(true); // the clientToken is now stored on the client
    }
  };

  if (!showAuth) {
    return <Button title="Sign in" onPress={start} />;
  }

  return (
    <MoonPayAuth
      onEvent={(event) => {
        if (event.kind === 'complete') onAuthenticated();
      }}
    />
  );
}

Mounting <MoonPayAuth> — or calling setupAuth() — without that prior getConnection() call emits an error event. On completion, credentials are applied to the shared client automatically, and event.payload.status is either active or termsAcceptanceRequired (see Connection statuses).

Get a quote and render the widget

import { useState } from 'react';
import { Button } from 'react-native';
import { MoonPayWidget, useMoonPay } from '@moonpay/platform-sdk-react-native';

function WidgetScreen() {
  const { client } = useMoonPay();
  const [quote, setQuote] = useState<string | null>(null);

  const loadQuote = async () => {
    const result = await client.getQuote({
      source: { asset: { code: 'USD' }, amount: '100' },
      destination: { asset: { code: 'BTC' } },
    });
    if (result.ok) {
      setQuote(result.value.data.signature);
    }
  };

  if (!quote) {
    return <Button title="Get quote" onPress={loadQuote} />;
  }

  return (
    <MoonPayWidget
      quote={quote}
      onEvent={(event) => {
        if (event.kind === 'complete') {
          console.log('Transaction complete', event.payload.transaction.id);
        }
      }}
    />
  );
}

Render an Apple Pay button

The button mounts inline at its natural size (height 48 by default). Quote updates are pushed into the frame without remounting:

import { MoonPayApplePayButton } from '@moonpay/platform-sdk-react-native';

<MoonPayApplePayButton
  quote={quoteSignature}
  onEvent={(event) => {
    switch (event.kind) {
      case 'complete':
        console.log('Paid', event.payload.transaction.id);
        break;
      case 'challenge':
        // Card issuer requires 3DS — see "Handle a 3DS challenge" below
        setChallengeUrl(event.payload.url);
        break;
      case 'quoteExpired':
        // Fetch a fresh quote and push it without remounting
        refreshQuote().then((signature) => event.payload.setQuote(signature));
        break;
      case 'unsupported':
        // Device or region does not support Apple Pay — render a fallback
        break;
    }
  }}
/>

<MoonPayGooglePayButton> and <MoonPayBuyButton> follow the same pattern.

Execute a buy headlessly

<MoonPayBuyFrame> executes a buy in a hidden WebView — your own UI stays in control the whole time. It needs an executable quote: one created with a wallet and paymentMethod. Render the frame when the customer confirms the purchase:

import { MoonPayBuyFrame } from '@moonpay/platform-sdk-react-native';

<MoonPayBuyFrame
  quote={quoteSignature}
  externalTransactionId="order-123"
  onEvent={(event) => {
    switch (event.kind) {
      case 'complete':
        console.log('Transaction complete', event.payload.transaction.id);
        break;
      case 'challenge':
        // Card issuer requires 3DS — see "Handle a 3DS challenge" below
        setChallengeUrl(event.payload.url);
        break;
      case 'error':
        console.error(event.payload.code, event.payload.message);
        break;
    }
  }}
/>

Like the payment buttons, quote is reactive — pushing a fresh signature does not remount the frame.

Handle a 3DS challenge

Payment frames (buy, buy button, Apple Pay, Google Pay) emit a challenge event when the card issuer requires verification. The event payload carries the full challenge URL:

// In the payment frame's onEvent handler:
case 'challenge':
  setChallengeUrl(event.payload.url);
  break;

Mount <MoonPayChallenge> with that URL. The challenge frame reports the final outcome itself — complete carries the finished transaction, and cancelled means the customer dismissed the verification. Unmount it on either event:

import { MoonPayChallenge } from '@moonpay/platform-sdk-react-native';

{challengeUrl && (
  <MoonPayChallenge
    url={challengeUrl}
    onEvent={(event) => {
      if (event.kind === 'complete' && event.payload.flow === 'buy') {
        console.log('Transaction complete', event.payload.transaction.id);
      }
      if (event.kind === 'complete' || event.kind === 'cancelled') {
        setChallengeUrl(null);
      }
    }}
  />
)}

Error handling

Methods never throw — they return Result<T, E>:

const result = await client.getPaymentMethods();

if (result.ok) {
  console.log(result.value.data);
} else {
  console.error(result.error.code, result.error.message);
}

What the SDK provides

Hook

  • useMoonPay() — returns the client from the nearest MoonPayProvider

Client methods

  • ConnectiongetConnection(), connect(), setupAuth() (requires a prior getConnection() call), resetConnection()
  • Payments datagetQuote(), getPaymentMethods(), deletePaymentMethod(), listTransactions(), getTransaction()
  • FramessetupWidget(), setupBuy(), setupChallenge(), setupAddCard(), setupCustomerExport()
  • CustomergetCustomer(), submitCustomerKyc(), getCustomerUploadUrl(), submitCustomerFiles() for headless integrations
  • Identity (deprecated, use Customer above)createIdentity(), getIdentity(), updateIdentity(), verifyIdentity() and file upload helpers

Components

| Component | Renders | |-----------|---------| | <MoonPayConnect> | Connect flow, inline | | <MoonPayConnectionCheck> | Headless connection check (nothing visible) | | <MoonPayConnectionReset> | Headless connection reset (nothing visible) | | <MoonPayAuth> | Email/OTP auth for headless / Customer API integrations — check the connection first | | <MoonPayCustomerExport> | Customer-export consent capture, inline | | <MoonPayWidget> | Full buy widget, inline | | <MoonPayApplePayButton> | Apple Pay button, inline | | <MoonPayGooglePayButton> | Google Pay button, inline | | <MoonPayBuyButton> | Card buy button, inline | | <MoonPayBuyFrame> | Headless buy execution (nothing visible) | | <MoonPayAddCard> | Card entry form, inline | | <MoonPayChallenge> | 3DS challenge, inline |

All visible components accept a style prop and an onEvent callback typed to that frame's events.

Related packages

| Package | Use it for | |---------|------------| | @moonpay/platform-sdk-node | Server-side session creation | | @moonpay/platform-sdk-web | Web apps | | @moonpay/platform-protocol | Shared protocol and API types |

Documentation

Platform guides and API reference: dev.moonpay.com

License

MIT