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
- Go to the Funding tab in your Dynamic developer dashboard.
- Under “Fiat on-ramps”, toggle on MoonPay and accept any additional terms.
- Save the settings.
Before continuing, make sure you’re using the latest version of the Dynamic SDK packages.
Once enabled, users will see MoonPay listed in the widget’s deposit screen. Selecting it opens the built-in MoonPay screen where they:
- Choose a token supported by MoonPay for their connected wallet’s chain.
- Review the destination wallet address.
- 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
| Prop | Type | Default | Description |
|---|
token | string | first available | MoonPay currency code to pre-select (e.g. 'eth', 'usdc_polygon'). Falls back to the first supported token if invalid. |
walletAddress | string | primary wallet | Override the destination wallet address shown in the widget. |
merchantName | string | — | Your app or merchant name shown to the user inside the MoonPay widget. |
onPaymentCreated | (url: string) => void | — | Callback receiving the signed MoonPay URL. When provided, the component does not open a popup — you control how the URL is used. |
onBack | () => void | navigate to provider list | Called when the user presses the back button. |
hideBackButton | boolean | false | Hide 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:
| Error | Cause |
|---|
MoonPayProviderNotAvailableError | MoonPay is not enabled for this environment, or no URL was returned for the requested chain/token. |
MoonPayInvalidUrlError | The 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)
}
}