Skip to main content

Overview

The MoonPay integration lets users buy crypto with fiat currency directly from your app. Once enabled, Dynamic shows a token selector screen inside the widget where the user picks a token, reviews the destination wallet, and is forwarded to MoonPay’s hosted checkout in a new tab. For a headless integration that bypasses the widget entirely, use the exported MoonPayOnramp component with an onPaymentCreated callback.

Dashboard Setup

  1. Go to the Funding tab in your Dynamic developer dashboard.
  2. Under “Fiat on-ramps”, toggle on MoonPay and accept any additional terms.
  3. Save the settings.
Before continuing, make sure you’re using the latest version of the Dynamic SDK packages.

Widget Implementation

Once enabled, users will see MoonPay listed in the widget’s deposit screen. Selecting it opens the built-in MoonPay screen where they:
  1. Choose a token supported by MoonPay for their connected wallet’s chain.
  2. Review the destination wallet address.
  3. Click Continue to MoonPay — Dynamic opens the signed MoonPay widget in a new tab.
No additional configuration is required for the default widget flow.

Programmatic Implementation

Using the useOnramp Hook

Use useOnramp to trigger the MoonPay flow from your own UI. Calling open with OnrampProviders.MoonPay navigates the Dynamic widget to the MoonPay token selector screen.
import { useOnramp } from '@dynamic-labs/sdk-react-core'
import { OnrampProviders } from '@dynamic-labs/sdk-api-core'

const MoonPayButton = () => {
  const { enabled, open } = useOnramp()

  const handleClick = async () => {
    await open({
      onrampProvider: OnrampProviders.MoonPay,
    })
  }

  return (
    <button onClick={handleClick} disabled={!enabled}>
      Buy with MoonPay
    </button>
  )
}
You can also pass address and token to pre-fill the widget:
await open({
  onrampProvider: OnrampProviders.MoonPay,
  address: '0x742d35Cc6634C0532925a3b844Bc9e7595f7ABCD',
  token: 'usdc',
})

Using the MoonPayOnramp Component

For a fully custom integration that bypasses the Dynamic widget, import MoonPayOnramp directly from @dynamic-labs/sdk-react-core. This renders a standalone token selector and wallet card that generates a signed MoonPay URL. Supply an onPaymentCreated callback to intercept the URL and handle it yourself instead of opening a popup:
import { MoonPayOnramp } from '@dynamic-labs/sdk-react-core'

const CustomMoonPay = () => {
  const handlePaymentCreated = (paymentUrl: string) => {
    // Open in a popup, embed in an iframe, or redirect
    window.open(paymentUrl, '_blank', 'width=500,height=700')
  }

  return (
    <MoonPayOnramp
      onPaymentCreated={handlePaymentCreated}
      token="usdc"
      merchantName="My App"
    />
  )
}
Without onPaymentCreated, the component opens MoonPay in a new tab automatically when the user confirms.

MoonPayOnramp Props

PropTypeDefaultDescription
tokenstringfirst availableMoonPay currency code to pre-select (e.g. 'eth', 'usdc_polygon'). Falls back to the first supported token if invalid.
walletAddressstringprimary walletOverride the destination wallet address shown in the widget.
merchantNamestringYour app or merchant name shown to the user inside the MoonPay widget.
onPaymentCreated(url: string) => voidCallback receiving the signed MoonPay URL. When provided, the component does not open a popup — you control how the URL is used.
onBack() => voidnavigate to provider listCalled when the user presses the back button.
hideBackButtonbooleanfalseHide the back button entirely.

Headless: Resolving the URL Only

If you only need the signed URL (e.g. to embed it in your own iframe), use getMoonPayUrl from @dynamic-labs-sdk/client:
import { getMoonPayUrl } from '@dynamic-labs-sdk/client'

const url = await getMoonPayUrl({
  chain: 'EVM',
  walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f7ABCD',
  token: 'usdc',
  currency: 'USD',
  networkId: '137', // Polygon
})

window.open(url, '_blank', 'width=500,height=700')
See the getMoonPayUrl and getMoonPayCurrencies reference docs for the full parameter list.

Customizing the Onramp Provider List

To customise how MoonPay appears alongside other providers, use the onrampOptions override in DynamicContextProvider:
<DynamicContextProvider settings={{
  overrides: {
    onrampOptions: (defaultOptions) =>
      defaultOptions.map((option) => {
        if (option.id === 'moonPay') {
          return { ...option, displayName: 'Buy Crypto' }
        }
        return option
      }),
  },
}}>
  <DynamicWidget />
</DynamicContextProvider>
See Customizing the Onramp Experience for the full OnrampOption structure and more examples.

Supported Tokens

Supported tokens vary by chain and network. Fetch them at runtime with getMoonPayCurrencies:
import { getMoonPayCurrencies } from '@dynamic-labs-sdk/client'

const currencies = await getMoonPayCurrencies({
  chain: 'EVM',
  networkId: '1', // Ethereum mainnet
})

currencies.forEach(({ code, name, icon }) => {
  console.log(code, name)
})
See the getMoonPayCurrencies reference for more details.

Error Handling

The MoonPayOnramp component surfaces errors inline. When using the hook or the headless API, handle these errors explicitly:
ErrorCause
MoonPayProviderNotAvailableErrorMoonPay is not enabled for this environment, or no URL was returned for the requested chain/token.
MoonPayInvalidUrlErrorThe returned URL failed host validation (https: + *.moonpay.com check).
import { getMoonPayUrl } from '@dynamic-labs-sdk/client'

const openMoonPay = async (walletAddress: string) => {
  try {
    const url = await getMoonPayUrl({
      chain: 'EVM',
      walletAddress,
      token: 'usdc',
      currency: 'USD',
    })
    window.open(url, '_blank')
  } catch (error) {
    console.error('Could not open MoonPay:', error.message)
  }
}