Skip to content

MoonPay ​

@openrampkit/adapter-moonpay is a fiat onramp through the MoonPay buy widget. It buys USDC with cards, Apple Pay, Google Pay, bank transfers, PIX, PayPal, Venmo, Revolut Pay and Interac.

New adapter

This adapter is new. Some provider details are marked TO VERIFY in the source (listed below).

ts
import { moonpay } from '@openrampkit/adapter-moonpay'

moonpay({
  publishableKey: process.env.MOONPAY_PUBLISHABLE_KEY!, // pk_live_... or pk_test_...
  secretKey: process.env.MOONPAY_SECRET_KEY!,           // sk_...
  webhookKey: process.env.MOONPAY_WEBHOOK_KEY,
  env: 'production',
})

To get the keys, see Get provider keys.

Options ​

OptionTypeDefaultDescription
publishableKeystringrequiredPublishable key
secretKeystringrequiredSecret key. Signs widget URLs.
env'sandbox' | 'production'requiredSandbox uses https://buy-sandbox.moonpay.com. The server checks env against livemode.
webhookKeystringnoneWebhook API key from the dashboard. Without it, webhooks are rejected.
surface'redirect' | 'iframe''redirect'How the widget opens
methodsstring[]allLeg ids to offer
deliverAssetsMoonPayDeliverAsset[]USDC on Base, Ethereum, Arbitrum, Optimism, PolygonAssets MoonPay may deliver, most preferred first. A destination token that is not in the list gets no quote (NO_QUOTES).
baseCurrencyDefaultstring'USD'Fiat currency when the quote has none
extraFeePercentagenumbernoneYour fee in percent (set it up with MoonPay first)
theme'dark' | 'light'noneWidget theme
apiUrl, widgetUrlstringMoonPay defaultsOverride the hosts

Legs ​

LegMethodMoonPay paymentMethodFiatCountries
cardcardcredit_debit_cardanyall allowed
apple_payapple_payapple_payanyall allowed
google_paygoogle_paygoogle_payanyall allowed
achachach_bank_transferUSDUS
sepasepasepa_bank_transferEUREEA and CH
gbp_bankfaster_paymentsgbp_bank_transferGBPGB
gbp_open_bankingopen_bankinggbp_open_banking_paymentGBPGB
pixpixpix_instant_paymentBRLBR
paypalpaypalpaypalanyall allowed
venmovenmovenmoUSDUS
revolut_payrevolut_payrevolut_payanyall allowed
interacinteracinteracCADCA
  • gbp_bank_transfer is UK Faster Payments. gbp_open_banking_payment is UK open banking. Source: widget parameters and the buy quote enum.
  • SEPA Instant has no separate MoonPay id. It is part of sepa_bank_transfer (supported payment methods).
  • Regions: a static deny list of countries where MoonPay does not allow buying (from the live API on 2026-09-29), plus US-VI. The live catalog (GET /v3/countries, cached for a day) replaces it with the current allowed countries and denied US states.
  • Some assets have extra limits: for example USDC on Base is not sold in New York or Canada. The quote then fails with REGION_UNSUPPORTED.

Quotes and start ​

  • Quote: GET /v3/currencies/{code}/buy_quote with areFeesIncluded=true, so the user pays exactly the amount they typed. Fees, in the fiat currency, all with included: true: the MoonPay fee (provider), the network fee (network) and your extra fee (app).
  • The guarantee is estimate: MoonPay sets the final rate when it executes. The quote expires at MoonPay's expiresAt, but at most 5 minutes from now (quoteExpiresAt(5, res.expiresAt)).
  • Start: a signed widget URL (base64 HMAC-SHA256 of the query string with the leading ?, appended as &signature=). It locks the amount, sets the wallet address, the method, externalTransactionId (the leg ref, ork_{random}), externalCustomerId (the user id), and redirectURL.
  • Status: GET /v1/transactions/ext/{externalTransactionId}. A 404 means the user has not paid yet.
  • providerRef: the MoonPay transaction id, from the first status or webhook that has it.
MoonPay statusLeg
completedsucceeded, with cryptoTransactionId as the destination transaction
pendingprocessing, detail code processing
waitingPayment, waitingAuthorizationrequires_action
failedfailed
otherno event: the adapter logs the unknown status once (statusMap), and the leg keeps its current step

The raw MoonPay status goes to detail.providerStatus.

Webhooks ​

Set the webhook URL in the MoonPay dashboard to {baseUrl}/webhooks/moonpay and pass the webhook API key as webhookKey.

  • Verification: header Moonpay-Signature-V2: t=<unix>,s=<hex>, HMAC-SHA256 of {t}.{body}, 5 minute tolerance. The adapter checks it with verifyTimestampedHmac from @openrampkit/adapter.
  • Events whose type starts with transaction_ are parsed with the same status mapping.

Sandbox limits ​

MoonPay test mode has USDC only as usdc (USDC on Ethereum). usdc_base, usdc_arbitrum, usdc_optimism and usdc_polygon are not in test mode. To test in test mode, quote USDC on Ethereum. A test mode quote for USDC on another chain fails. Base is first in the default deliverAssets, so set the destination to USDC on Ethereum for test mode. Checked on 9 Oct 2026. See Get provider keys.

Verified vs TO VERIFY ​

  • TO VERIFY: the recommended iframe allow list.
  • TO VERIFY: Venmo through MoonPay is US-only.
  • TO VERIFY: the webhook signature is hex (inferred from the example in the docs).

MIT licensed